(原)关于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,即使网络缓冲区满了,他也会立即返回,不会进行阻塞等待,所以这种情况下适合于流媒体发送数据,即使单线程作战分发也是可以的。

 

原文地址:https://www.cnblogs.com/lihaiping/p/6811791.html