如果带有MSG_PEEK的非阻塞recv成功,那么没有MSG_PEEK的后续recv是否也会成功?

时间:2009-05-14 17:42:11

标签: sockets nonblocking recv

以下是我正在处理的一些代码的简化版本:

void
stuff(int fd)
{
    int ret1, ret2;
    char buffer[32];

    ret1 = recv(fd, buffer, 32, MSG_PEEK | MSG_DONTWAIT);

    /* Error handling -- and EAGAIN handling -- would go here.  Bail if
       necessary.  Otherwise, keep going.  */

    /* Can this call to recv fail, setting errno to EAGAIN?  */
    ret2 = recv(fd, buffer, ret1, 0);
}

如果我们假设第一次调用recv成功,返回1到32之间的值,是否可以安全地假设第二次调用也会成功? ret2能否小于ret1?在哪些情况下?

(为清楚起见,假设在第二次调用recv期间没有其他错误条件:没有信号传递,它不会设置ENOMEM等。还假设没有其他线程会查看fd。

我在Linux上,但我相信MSG_DONTWAIT是这里唯一的Linux特有的东西。假设之前在其他平台上设置了正确的fnctl。)

5 个答案:

答案 0 :(得分:8)

POSIX标准规定,对于MSG_PEEK,“数据被视为未读,下一个recv()或类似函数仍将返回此数据。”这似乎意味着除非ret2为-1,否则它将与ret1相同。

答案 1 :(得分:5)

您还必须考虑在ret1和ret2之间调用不同线程上的不同recv调用的可能性。另一个调用将获取您的数据,使ret2最终没有数据,或意外地减少数据。

如果您的应用程序不是多线程的,或者设计为只有这两个调用使用fd,那么您可以忽略它。但如果这是一个风险,那么你应该把两个调用放在一个锁定机制中。

答案 2 :(得分:2)

没有MSG_PEEK的第二次调用recv()可能会因EINTR失败或返回不完整的数据,因为它已被信号中断。

答案 3 :(得分:1)

我不确定EAGAIN,但认为EBADF或ECONNRESET是可能的。

答案 4 :(得分:0)

对于您的简单情况,后续recv将返回ret1个字节数(如果ret1不是错误)。但是,对于多线程设计,它可能并非总是如此。