轉載請注明出處: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,即使網絡緩沖區滿了,他也會立即返回,不會進行阻塞等待,所以這種情況下適合於流媒體發送數據,即使單線程作戰分發也是可以的。