为了账号安全,请及时绑定邮箱和手机立即绑定

您好,关于recvfrom()的一次调用只能返回一个UDP包。这种说法正确吗?

您好,关于recvfrom()的一次调用只能返回一个UDP包。这种说法正确吗?

桃花长相依 2021-11-04 11:07:58
1.recvfrom()的一次调用只能返回一个UDP包。此种说法正确吗?2.send()和sendto()函数参数中的buffer有长度限制吗?我对左稚幻回答的第二条有疑问:我一个程序中,接收端一下发了1024*1024字节(一次send调用,设置buffer为1024*1024长,全填满了数据),接收端也用一次recv调用(提供了1024*1024长的缓冲区),能一次完全接收到发送的1024*1024个字节。为什么?(我是在本机上测试的)
查看完整描述

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参数,如果还有问题敬请指出:)



查看完整回答
反对 回复 2021-11-09
?
心有法竹

TA贡献1866条经验 获得超5个赞

你看他的参数明显一次只能返回一个啊
UDP发送的包尺寸超过网络允许的大小,发送行为将会失败。
即便对方马上就接受也未必接受得到。UDP有一个缓冲区,发过来的包会放在缓冲区里,recv是从这个缓冲区里面读取。所以send之后一段时间再调用recv是可以接收到这个包的,前提是这个包成功被放入缓冲区了。但是如果send的时候缓冲区已经满了,或者发送时发生了错误,这样不管你什么时候recv都得不到这个包。

查看完整回答
反对 回复 2021-11-09
  • 2 回答
  • 0 关注
  • 491 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信