• 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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.组播

     

        

  • 相关阅读:
    2013年4月20日
    关于"退耦"
    关于PCB原理图中的FBFB是磁珠的符号电子元器件电路图
    搜索技巧总结
    收集 QQ旋风离线下载帐号
    转载一篇日志
    硬件原理图和实物对比理解_EM310模块电路
    硬件原理图和实物对比理解_zigbee模块
    硬件原理图和实物对比理解_LPC电源模块
    word无法读取此文件,文档可能已损坏_可能的补救方法
  • 原文地址:https://www.cnblogs.com/Lune-Qiu/p/8532971.html
Copyright © 2020-2023  润新知