UDP数据报

服务器端:Server

函数:

1.inet_addr();//把IP地址转换为长整型
2.inet_ntoa();//将长整型转换为IP地址
3.socket的阻塞和非阻塞:

阻塞模式下:

在程序中,“生产者”读入数据,“消费者”根据需求对读入数据进行处理。通常“生产者”和“消费者”存在于两个线程中,当“生产者”完成读入数据时,使用线程同步机制,例如设置一个事件通知“消费者”,“消费者”接收到这个事件后对读入的数据进行处理。

并不是所有Windows Sockets API以阻塞套接字为参数调用都会发生阻塞。例如,以阻塞模式的套接字为参数调用bind()、listen()函数时,函数会立即返回。将可能阻塞套接字的Windows Sockets API调用分为以下四种:

1.输入操作

recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。如果此时套接字缓冲区内没有数据可读,调用线程在数据来前一直睡眠。

2.输出操作

send()、sendto()、WSASend()和WSASendto()函数。如果套接字缓冲区没有可用空间,线程会一直睡眠,直到有空间。

3.接受连接

accept()和WSAAcept()函数。等待接受对方的连接请求。如果此时没有连接请求,线程就会进入睡眠状态。

4.外出连接

connect()和WSAConnect()函数。对于TCP连接,客户端以阻塞套接字为参数,调用该函数向服务器发起连接。该函数在收到服务器的应答前,不会返回。这意味着TCP连接总会等待至少到服务器的一次往返时间。

非阻塞模式:

ioctlsocket();//设置socket属性为阻塞或非阻塞;Linux下的函数是:fcntl().
WSAAsyncselect()和WSAEventselect()套接字自动设置为非阻塞
应用程序连续不断地调用recv()函数,直到它返回成功指示为止。浪费系统资源。
解决方法:使用套接字的“I/O模型”来判断非阻塞套接字是否可读可写。

4.getsockopt();//获取输入缓冲区和输出缓冲区的大小(65536即64K)
#include <iostream>
#include <winsock2.h>

using namespace std;
#pragma comment(lib, "ws2_32.lib")

int main()
{
    //1.WSAStartup
   WSADATA wsaData;
   WORD wVersionRequested = MAKEWORD(2, 2);
    int err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }
    //2.socket
    SOCKET sock = socket(AF_INET ,SOCK_DGRAM ,IPPROTO_UDP );
    if(sock == INVALID_SOCKET)
    {
        printf("socket function failed with error = %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //3.bind
     sockaddr_in name;
     name.sin_family = AF_INET;
     name.sin_addr.S_un.S_addr = inet_addr("192.168.1.115");
     name.sin_port = htons(1234);
    int res = bind(sock,(sockaddr *)&name,sizeof(name));
    if(res == SOCKET_ERROR)
    {
        printf("socket function failed with error = %d\n", WSAGetLastError());
        closesocket(sock);
        WSACleanup();
        return 1;
    }
    //改变Socket属性为非阻塞
    //u_long nonzero = 1;
    //ioctlsocket(sock ,FIONBIO ,&nonzero );//设为非阻塞(非零)
    int SendbufSize,RecvbufSize;
    int nsize = sizeof(SendbufSize);
    getsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&SendbufSize,&nsize);
    getsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char*)&RecvbufSize,&nsize);
    cout<<"SendbufSize: "<<SendbufSize<<"    RecvbufSize: "<<RecvbufSize<<endl;
    
    //4.recvfrom , sendto
    char recvbuf[1024] = {0};//接收
    sockaddr_in addr;
    int len = sizeof(addr);
    char sendbuf[1024] = {0};//发送

    while(1)
    {
        int nres = recvfrom(sock,recvbuf,sizeof(recvbuf),0,(sockaddr *)&addr,&len);
        int n = nres;//-1
        int nn = WSAGetLastError();
        if(nres != 0)
        {
            cout<<"ip"<<inet_ntoa(addr.sin_addr)<<":"<<recvbuf<<endl;
            //cin>>str;
            //sendto(sock,sendbuf,sizeof(sendbuf),0,(sockaddr *)&addr,len);
        }
    }
    //5.WSACleanup
    closesocket(sock);
    WSACleanup();
    system("pause");
    return 0;
}

客户端:

函数:setsockopt()//设置广播权限

客户端可以通过bind绑定服务器,sendto的后两个参数就可以不用设置,bind实现的其实是本地设置,告诉本地操作系统,默认发送地址,当sendto的后两个参数设置,即按地址发送。

#include <iostream>
#include <winsock2.h>

using namespace std;
#pragma comment(lib, "ws2_32.lib")

int main()
{
    //1.WSAStartup
   WSADATA wsaData;
   WORD wVersionRequested = MAKEWORD(2, 2);
    int err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }
    //2.socket
    SOCKET sock = socket(AF_INET ,SOCK_DGRAM ,IPPROTO_UDP );
    if(sock == INVALID_SOCKET)
    {
        printf("socket function failed with error = %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //4.sendto , recvfrom 
     sockaddr_in name;
     name.sin_family = AF_INET;
     name.sin_addr.S_un.S_addr = inet_addr("255.255.255.255");
     name.sin_port = htons(1234);//host to net short
    int len = sizeof(name);
    char buf[1024] = {0};
    //设置广播权限
    BOOL bflag  = TRUE;
    setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char *)&bflag , sizeof(bflag));

    while(1)
    {
        cin>>buf;
        int n = sendto(sock,buf,sizeof(buf),0,(sockaddr *)&name,len);
        int nn = GetLastError();
        //int nres = recvfrom(sock,buf,sizeof(buf),0,0,0);
        //if(nres > 0)
        //{
        //    cout<<buf<<endl;
        //}
    }
    //5.WSACleanup
    closesocket(sock);
    WSACleanup();
    system("pause");
    return 0;
}

 

UDP:1.面向无连接(广播) 有限广播(255.255.255.255):本局域网内传输,不能跨路由器  

              直接广播(192.168.3.255)      :本网段内传输,可以跨路由器

    2.数据报(不可拆分)当接收区容量小于发送区时,丢弃多余部分

    3.传输效率高(无延迟):报头8字节

    4.组播

 

    

posted @ 2018-03-09 11:38  Lune-Qiu  阅读(631)  评论(0编辑  收藏  举报