zoukankan      html  css  js  c++  java
  • (原)关于udp的socket发送数据耗时的问题探讨

    转载请注明出处:http://www.cnblogs.com/lihaiping/p/6811791.html

    本学习笔记,仅用于问题探讨,如有不同,可以讨论。

    最近在看流媒体分发服务器的相关代码,其中对于网络udp数据发送耗时的研究,这块有一点点疑问:

    udpsendto发送数据的耗时大概为多少?他的耗时跟发送的数据包大小有没有关系?跟对端的ip地址是否存在,有没有关系?是否存在ip地址在的网络,sendto耗时小,对于ip地址网络不通的耗时是不是比较大?

    网络搜索,csdn论坛有人问了:http://bbs.csdn.net/topics/60039818

    然后我拷贝了论坛的测试程序,在vs上运行测试了一把,同时进行了部分修改。

    //测试网络发送耗时问题
    int udp_socket_send_test(int argc, char* argv[])
    {
        DWORD    LastTime;
        DWORD    Curtime;
        DWORD    EscpTime;
        WSADATA        wsaData;
        long    addr;
        long    wrc;
        long    lngSendTimeOut = 1000;
        long    lngRecvTimeOut = 1000;
        SOCKADDR_IN sockObject;
        SOCKET    sSend;
        u_long nonblocking = 1;
        char    transbuf[1000] ;//这个地方的数据大小,只是跟填充网络发送缓冲区有关
        char    IPADDR[17];
        memset(transbuf,'a',sizeof(transbuf));
    
        WSAStartup(0x202,&wsaData);
        sSend = socket(AF_INET, SOCK_DGRAM,0);
        //设置为非阻塞模式
        ioctlsocket(sSend,FIONBIO,&nonblocking);//在非阻塞模式下,udp发送基本不占用时间,而且跟ip地址无关系
        setsockopt(sSend,SOL_SOCKET,SO_SNDTIMEO, (char*)&lngSendTimeOut,sizeof(lngSendTimeOut) );
        setsockopt(sSend,SOL_SOCKET,SO_RCVTIMEO,(char*)&lngRecvTimeOut,sizeof(lngRecvTimeOut) ); 
        sockObject.sin_port = htons(3500);
        sockObject.sin_family = AF_INET;
        for(int i = 1;i < 35; i++)
        {
            sprintf(IPADDR,"192.168.0.1%d",i);
            LastTime = GetTickCount();
            addr = inet_addr((char *)IPADDR);
            memcpy(&sockObject.sin_addr,&addr,sizeof(addr));
            //这个地方的耗时跟两个因素有关系
            //官方:
            //If no buffer space is available within the transport system to hold the data to be transmitted, 
            //sendto will block unless the socket has been placed in a nonblocking mode. 
            //也就是说,对于sendto函数,他的发送返回成功并不代表网络发送了,他只是将数据发送到传输层的缓冲区,就返回结果
            //而对于阻塞的socket,当这个ip地址即使不存在,但缓冲区未满的情况下,他也是返回成功的,而且基本不耗时,
            //但当缓冲区满了以后,sendto就会阻塞,这个时候会产生耗时
            //对于非阻塞的socket,缓冲区未满的时候,它基本不占发送时间,满了,sendto也会立即返回结果,整个过程基本不耗时
    
            wrc = sendto(sSend,transbuf,sizeof(transbuf),0,(struct sockaddr *)&sockObject,sizeof(sockObject));    
            Curtime = GetTickCount();
            EscpTime = Curtime - LastTime;
            if (wrc != SOCKET_ERROR) 
            {
                printf("Send Some Data To %s,Use Time:%d ms
    ",IPADDR,EscpTime);
                //    Sleep(1000);
            }
            else 
            {
                printf("*Send Some Data To %s,failed ,Use Time:%d ms,sendto return value:0x%x
    ",IPADDR,EscpTime,wrc);
            }
            Sleep(1);
    
        }
        closesocket(sSend);
        WSACleanup();
        return 0;
    }

    上面是我测试的时候的一个源码。

    然后我在srs论坛里面也跟群友咨询了这个问题,他的拷贝了一个官方的解释给我:

    If no buffer space is available within the transport system to hold the data to be transmitted, sendto will block unless the socket has been placed in a nonblocking mode. 

    直接翻译过来的意思为:

    如果没有可用的缓冲区空间运输系统内的数据传输、sendto将阻止,除非socket被放置在一个非阻塞模式。

    然后我在源码里面也进行注释:

    udp 的sendto函数,其实他只是将发生的数据包进行了一次拷贝,拷贝到了传输层的网络缓冲区,然后函数返回结果。所以sendto函数的返回值并不能代表网络真实的一个发送情况结果。既然理解了上面的这个,所以udp的sendto耗时基本可以忽略了。因为数据拷贝基本不占用多大实际时间。但对于阻塞的socket,当网络缓冲区满了以后,sendto就会阻塞。而对于非阻塞的socket,即使网络缓冲区满了,他也会立即返回,不会进行阻塞等待,所以这种情况下适合于流媒体发送数据,即使单线程作战分发也是可以的。

     

  • 相关阅读:
    解决spring boot JavaMailSender部分收件人错误导致发送失败的问题
    Linux设备驱动开发基础--内核定时器
    Linux中断分层--工作队列
    Linux中断分层--软中断和tasklet
    深入理解函数线程安全与可重入
    Linux中断处理流程
    Linux混杂设备驱动--按键设备驱动
    Linux字符设备驱动--Led设备驱动
    Linux字符设备简单示例
    Linux内核硬件访问技术
  • 原文地址:https://www.cnblogs.com/lihaiping/p/6811791.html
Copyright © 2011-2022 走看看