recvfrom()的一次调用只能返回一个UDP包。此种说法正确吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了recvfrom()的一次调用只能返回一个UDP包。此种说法正确吗?相关的知识,希望对你有一定的参考价值。

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

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参数,如果还有问题敬请指出:)
参考技术A 你看他的参数明显一次只能返回一个啊

UDP发送的包尺寸超过网络允许的大小,发送行为将会失败。

即便对方马上就接受也未必接受得到。UDP有一个缓冲区,发过来的包会放在缓冲区里,recv是从这个缓冲区里面读取。所以send之后一段时间再调用recv是可以接收到这个包的,前提是这个包成功被放入缓冲区了。但是如果send的时候缓冲区已经满了,或者发送时发生了错误,这样不管你什么时候recv都得不到这个包。

【奇】udp的recvfrom

A创建一个udp套接字, 绑定到(IP1, PORT1), 开两个线程, 一个发送, 一个接收
B也是创建一个udp套接字, 绑定到(IP2, PORT2), 开两个线程, 一个发送, 一个接收
A和B相互可以发送和收到数据
然后B关闭套接字退出, 重新创建一个udp套接字, 绑定到(IP2, PORT3), 开两个线程, 一个发送, 一个接收
【注意】调试的时候, 发现在A调用recvfrom()后, 参数from的地址自动变成(IP2, PORT3), 并能接收到C发来的数据, C也可以接收到A
怎么会出现这样的情况, recvfrom()函数为什么会改变from参数的值?
===========================================================
后来在同一台机子上调试也是一样, 只要B退出重新绑定到新的端口, A在调用recvfrom()后, from的端口会自动变成B的【新端口】, A和B双方又可以通信了, 非常奇怪, 不是吗?
====================
A和B的套接字都把SIO_UDP_CONNRESET选项设置为false, 不知道是这个的原因不????

UDP本来就是这样的,不需要绑定IP,只需要绑定一个端口,Sendto函数会附带IP信息,recv的时候会解析进来连接的地址。因为udp没有固定的连接,所以不知道进来的连接的IP,只能通过recv函数去实时获取,这是UDP最基本的机制。追问

'不需要绑定IP'是什么意思, 直接绑定0.0.0.0旧可以吗, sendto()会自动找到一个合适的本地ip?

recvfrom会自动解析对方地址, 哪还要from参数干什么, 这样recvfrom()的套接字不成了类似TCP的监听套接字吗?接收不乱套了吗?而且微软关于recvfrom()的官方文档上没有这样的说明啊!

大哥能不能提相关资料

追答

绑定地址的时候,如果只绑定端口,表示接受该端口下任何IP发来的数据,如果绑定IP和端口表示接受该IP和端口的数据,然后recvfrom函数在流中有数据可读的时候,会把该数据源的IP和端口解析出来,然后再根据该IP做相应的处理就可以了。UDP对端地址信息,都是从recvfrom函数中读取出来的。

追问

1, 还是不明白, 只绑定端口的话, bind()参数中的sockaddr_in.sin_addr该怎么填写

2, recvfrom()的参数form表明要接收指定ip和port的数据, 为什么还会收到其他端口的消息

3, 照你这样说的好像udp不遵守五元组原则啊, 本例中的五元组是(udp, ip1, port1, ip2, port2)
A的五元组没变, 却收到了(ip2, port3)的消息

追答

额...先了解一下UDP通信的一些基本概念吧,网上应该有很多啊,如果只绑定端口的话,sin.addr可以不用管啊。

recvfrom()接收绑定地址上发来的数据,也就是bind了什么地址,就接受什么地址的数据,如果只绑定一个端口,就接受这个端口所有IP发过来的数据。
这个函数的那个地址参数,是这个数据报的源地址,也就是谁发过来的。也就是说这个函数的地址参数是输出的,不是输入的。

比如说你只绑定了一个端口,然后收到了一条数据,这个数据来源的IP是什么呢,那就是recvfrom这个函数中解析出来的地址了。

参考技术A 你的from是哪个值?追问

追答

我的意思是你的from值从哪里读取的?

追问

两个线程共用一个套接字和from, 都是全局变量, 一个senddo()发送, 一个recvfrom()接收, 而且不会是sendto()改变from的, 已经单步调试过了
from是已知的, 因为实验中A和B都是用已知的ip和端口绑定, 而且在from的所有实例上下了断点, 只有recvfrom()函数会改变from的值.

以上是关于recvfrom()的一次调用只能返回一个UDP包。此种说法正确吗?的主要内容,如果未能解决你的问题,请参考以下文章

终端通过GPRS发送UDP数据到固定IP:端口号,socket recvfrom接收不到数据,但却有返回值,如何解决

UDP并发客户端recvfrom错误

【奇】udp的recvfrom

UDP 套接字上的 recvfrom() 返回 -1 但 WSAGetLastError() 返回 0

关于UDP数据报引发“异步错误”的疑问

UDP和套接字,recvfrom()返回-1,资源暂时不可用