2 回答

TA貢獻1934條經驗 獲得超2個贊
1.一次recvfrom()調用只能返回一個UDP數據包。
2.send()函數參數中的buffer長度有限制,此長度限制取決于底層協議的數據包最大長度,這個長度可以通過getsockopt函數設置SO_MAX_MSG_SIZE參數獲得,如果發送的數據包超過底層協議的最大長度則返回WSAEMSGSIZE錯誤,同時不發送任何數據。
sendto()函數參數中的buffer長度也有限制,這個限制更明顯一些,數據包的數據部分(不包括數據頭)的長度不能超過512字節。
3.send()與sendto()正常返回均不能保證發送的數據被接受方正確接收,還要看緩沖區是否已滿。當緩沖區為空時,recv與recvfrom均阻塞等待(除非設置為非阻塞,此時將返回WSAEWOULDBLOCK錯誤),因此只要socket正常連接,且緩沖區有數據內容,recv與recvfrom函數雖延遲但均能正常接收數據包。
希望我的回答你能滿意:)
你好,我看了你添加的內容,我上面所說的最大長度512字節是指UDP數據包可以發送的的最大長度,針對的是sendto函數,而你測試時使用的則是TCP連接中的send函數,兩者使用的協議不同,因此緩沖區的長度當然不同了,我使用getsockopt測試,得到我本機接受方的最大緩沖為8192字節,測試代碼如下:
#include <stdio.h>
#include "winsock2.h"
void main() {
WSADATA wsaData;
SOCKET ListenSocket;
sockaddr_in service;
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
if( iResult != NO_ERROR )
printf("Error at WSAStartup\n");
ListenSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if (ListenSocket == INVALID_SOCKET) {
printf("Error at socket()\n");
WSACleanup();
return;
}
hostent* thisHost;
char* ip;
u_short port;
port = 27015;
thisHost = gethostbyname("");
ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr(ip);
service.sin_port = htons(port);
if ( bind( ListenSocket,(SOCKADDR*) &service, sizeof(service) ) == SOCKET_ERROR ) {
printf("bind failed\n");
closesocket(ListenSocket);
return;
}
int optVal;
int optLen = sizeof(int);
getsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&optVal, &optLen);
printf("The max length is %d\n", optVal);
WSACleanup();
return;
}
在此補充一下,上面所說SO_MAX_MSG_SIZE只針對UDP這種數據報形式的協議有效,而對于基于流的TCP/IP無效,因此在此使用SO_RCVBUF參數,如果還有問題敬請指出:)

TA貢獻1866條經驗 獲得超5個贊
你看他的參數明顯一次只能返回一個啊
UDP發送的包尺寸超過網絡允許的大小,發送行為將會失敗。
即便對方馬上就接受也未必接受得到。UDP有一個緩沖區,發過來的包會放在緩沖區里,recv是從這個緩沖區里面讀取。所以send之后一段時間再調用recv是可以接收到這個包的,前提是這個包成功被放入緩沖區了。但是如果send的時候緩沖區已經滿了,或者發送時發生了錯誤,這樣不管你什么時候recv都得不到這個包。
添加回答
舉報