长度为零的recv()是否有效?
使用C中的recv()函数从“stream”套接字读取,len参数是否可以为零 recv()函数为“remote connection closed”(远程连接已关闭)返回零,并返回正常操作中实际读取的字节数,因此如果读取零字节,则听起来有问题 附加说明长度为零的recv()是否有效?,c,sockets,C,Sockets,使用C中的recv()函数从“stream”套接字读取,len参数是否可以为零 recv()函数为“remote connection closed”(远程连接已关闭)返回零,并返回正常操作中实际读取的字节数,因此如果读取零字节,则听起来有问题 附加说明 是的,我知道要单独处理它,但我不知道这个函数是否可以处理它,我找不到任何关于它的文档。我认为长度参数不能为零,因为即使是空字符串(消息)也需要以“\0”结尾。我很确定它没有定义。。。看看Linux,它一直传递到“驱动程序”(如tcp等),所以它
是的,我知道要单独处理它,但我不知道这个函数是否可以处理它,我找不到任何关于它的文档。我认为长度参数不能为零,因为即使是空字符串(消息)也需要以“\0”结尾。我很确定它没有定义。。。看看Linux,它一直传递到“驱动程序”(如tcp等),所以它可能意味着什么,但我认为这一含义并没有得到很好的定义。当然,SuS并没有明确说明这一点 我认为你最好不要这样做,根据你想做的事情使用带有1字节的MSG_PEEK或poll()。我相信答案是“视情况而定”如果标准中没有指定它(事实上我相信不是),任何实现都可以随心所欲
- 如果出现
EINVAL
- 它可以挂起来
- 它可以返回
并继续0
- 它可以打印一条有趣的消息,并启动游戏rogue(我理解,
用于这样做:))gcc
实际上在我的实现中,它返回0并继续。要检查它是否失败或只是返回了0,您可以在调用后检查
errno
,这样就不会像您想象的那样有问题了。我的系统(Linux)上的recv
文档中说
如果套接字上没有可用的消息,则接收呼叫将等待消息到达
及
如果消息太长,无法放入提供的缓冲区,则可能会丢弃多余的字节,具体取决于从中接收消息的套接字类型。
根据文档,我希望我的recv
等待消息,然后有效地丢弃它(UDP)或将它留在流中(TCP)
这可用于测试非阻塞TCP套接字是否有数据等待
更新:测试表明该文档的解释是准确的
服务器:
$ perl -MIO::Socket::INET -E'
my $s = IO::Socket::INET->new(Listen => 1) or die $!;
say $s->sockport;
my $c = $s->accept or die $!;
say "[".localtime."] connected";
$c->recv(my $buf, 0) // die $!;
say "[".localtime."] received";
say <$c>;
'
39493
[Fri May 13 13:49:53 2011] connected
[Fri May 13 13:49:55 2011] received
foo
(这些Perl函数只是系统调用的瘦接口。请随意用C重写它们。)POSIX关于
recv()
的页面并不清楚。在非规范性部分(“应用程序用法”)中,如果未给出任何标志,则表示套接字上的recv()
等同于read()
。POSIX关于read();如果没有错误或实现没有检查,则不会发生任何事情,并返回0。不确定这有什么问题吗?当您要求read()读取0字节时,您希望它返回什么?1? -1?@BlackBear,还没有,如果有人知道,我更愿意得到答案,而不是构造一个测试-处理套接字,即使是最简单的测试也需要设置要连接的东西,建立连接,然后尝试看看会发生什么。我刚刚在Windows上在阻塞套接字TCP上进行了尝试recv(s,b,0,0)
挂起,直到有一些传入数据或连接关闭,然后返回0。如果已经有传入数据,它会立即返回0WSAGetLastError()
和errno
在此之后返回0。来自套接字的“消息”不一定是以nul结尾的字符串。。。。它也不一定是一根弦:-好的,我的坏。注意。尽管C语言允许使用零字节缓冲区,但我仍然认为这一概念值得商榷。我的系统(Linux)上的文档清楚地定义了recv
的行为,而缓冲区长度为零并不能阻止任何这种行为。我不明白为什么你认为零在某种程度上是异常的,并且在某种程度上是异常的,以至于定义的行为应该被忽略,所以我认为你的答案是错误的。请参阅我的答案以了解详细信息。正如我所说的,我觉得这可能是一个问题,因为返回值很奇怪。我不知道也不确定这就是我问的原因。返回零通常意味着插座已关闭。因此,当给定的长度为零时,recv()无法返回任何有意义的内容,除了EINVAL。所以,永远不要调用length=0的recv()。虽然这是可行的,但perl的行为方式可能是这样的,而C的实现不会这样吗?可能是这个“薄接口”也用一些边缘案例处理来包装它。我很感激你的回答,但我仍然觉得“视情况而定”是更准确的答案。当(如果有的话)我最终将自己测试它时,我可能会在这里更新。@Xenorose,我使用的是系统文档(man recv
),而不是Perl。如果你发邮件给我,我们非常欢迎你用C语言重新实现测试(ikegami@adaelis.com),我甚至会用它替换我答案中的Perl代码。
$ perl -MIO::Socket::INET -E'
my $s = IO::Socket::INET->new(
PeerAddr => "127.0.0.1",
PeerPort => $ARGV[0],
) or die $!;
sleep 2;
say $s "foo";
' 39493