转载请注明出处:http://www.cnblogs.com/lihaiping/p/6811791.html
本学习笔记,仅用于问题探讨,如有不同,可以讨论。
最近在看流媒体分发服务器的相关代码,其中对于网络udp数据发送耗时的研究,这块有一点点疑问:
udp的sendto发送数据的耗时大概为多少?他的耗时跟发送的数据包大小有没有关系?跟对端的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\n",IPADDR,EscpTime); // Sleep(1000); } else { printf("*Send Some Data To %s,failed ,Use Time:%d ms,sendto return value:0x%x\n",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,即使网络缓冲区满了,他也会立即返回,不会进行阻塞等待,所以这种情况下适合于流媒体发送数据,即使单线程作战分发也是可以的。