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

Mic*_*olf 12 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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

小智 9

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


abe*_*nky 5

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

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

  • 即使使用单线程程序,其他人也可以在这两个`recv`调用之间获取数据:打开相同套接字文件描述符的另一个进程可能会获取数据.同一进程中的信号处理程序也可能获取数据.(幸运的是,代码中的信号处理程序通常很容易控制.) (3认同)

Nik*_*sov 2

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