2011-05-13 51 views
10

使用C中的recv()函数从'流'套接字读取len参数可以为零吗?长度为零的recv()是否有效?

recv()函数对于'远程连接关闭'返回零和正常操作中实际读取的字节数,所以如果它应该读取零字节听起来有问题。

P.S.
是的,我知道单独处理它,并没有得到这种情况,我仍然想知道该功能是否可以处理它,我找不到任何有关它的文档。

+3

你试过了吗? – BlackBear 2011-05-13 16:21:40

+0

不确定为什么这是有问题的?当你要求它读取0字节时,你期望read()返回什么? 1? -1? – stijn 2011-05-13 16:26:27

+0

@BlackBear,还不如,如果有人知道构建一个测试,我宁愿得到答案 - 即使最简单的测试需要设置某些东西来连接,建立连接,然后尝试看看会发生什么。 – Eran 2011-05-13 16:33:56

回答

4

我相信答案是“取决于”。 如果它没有被标准(并且实际上我相信它不是)规定的,任何实现都可以按照它的意愿进行。

  • 它可能会失败,EINVAL
  • 它可以挂
  • 它可以返回0,继续
  • 它可以打印一个有趣的消息,并开始游戏流氓(我的理解来做到这一点gcc: )))

其实在我的实现中,它返回0并继续。要检查它是否失败或只是返回0,您可以在电话后检查errno,因此它不像您想象的那样有问题。

+2

我可以生活在“取决于”......谢谢。 – Eran 2011-05-13 16:49:44

+0

我的系统(Linux)上的文档清楚地定义了'recv'的行为方式,并且没有任何关于阻止任何这种行为的缓冲区长度为零。我不明白为什么你认为零是某种特殊的东西,并且某种程度上非常特殊,以至于所定义的行为应该被忽略,所以我认为你的答案是错误的。详情请参阅我的回答。 – ikegami 2011-05-13 17:59:28

+0

正如我所说,我认为这可能是一个问题,由于返回值,通常是因为它很奇怪。我不知道,也不确定这是为什么我问。 – Eran 2011-05-13 18:30:03

-3

我不认为长度参数可以是零,因为即使是一个空字符串(消息)需要终止'\ 0'。

+2

来自套接字的“消息”不一定是以nul结尾的字符串。 – 2011-05-13 16:29:14

+1

...并不一定是一个字符串:-D – 2011-05-13 16:31:05

+0

好吧,我的坏。注意到了。尽管C语言允许,但我仍然认为零字节缓冲区的概念值得商榷。 – 2011-05-13 18:10:38

1

我很确定它是未定义的......看着Linux它一直传递到“驱动程序”(即.tcp等),所以它可能意味着什么,但我不认为这是意义被很好地定义。当然,SuS并没有对此做任何明确的说明。

我认为你几乎可以肯定不会这样做,并且根据你想要做的事情使用带有1字节或poll()的MSG_PEEK。

3

recv我的系统(Linux)的有关文档说

如果没有消息可在插座,接收呼叫等待消息的到达

如果消息是太长以至于无法装入所提供的缓冲区中,取决于从中接收消息的套接字的类型,可能会丢弃多余的字节。

根据文档,我期望我的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 -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 

(这些Perl函数只是瘦接口的系统调用随意改写他们在C.)

+0

虽然这可行,但是perl可以这样做,但是C的实现不会呢?难道这个“精简界面”也会用一些边缘处理来包装它。我感谢你的回答,但仍然觉得解释“这取决于”是更准确的答案。什么时候(以及如果有的话)我最终会自己测试一下,我可能会在这里更新。 – Eran 2011-05-13 18:33:22

+0

@Xenorose,我去了* system *文档('man recv'),而不是Perl的。如果您通过电子邮件发送给我([email protected]),我甚至会用我的答案替换Perl代码。 – ikegami 2011-05-13 20:04:10

0

POSIX的页面约recv()是不是很清楚它。在非标准部分(“应用程序使用”)中,如果没有给出标志,则说明在套接字上的recv()相当于read()。 POSIX的页面read()表示读取0字节可能会检查错误;如果没有错误或执行不检查,则不会发生任何事情并返回0。

相关问题