14

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

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。)

4

5 回答 5

10

POSIX 标准规定了关于MSG_PEEK

数据被视为未读,下一个 recv() 或类似函数仍将返回此数据

这似乎意味着除非ret2-1,否则它将与 相同ret1

于 2009-05-15T00:03:08.057 回答
5

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

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

于 2009-05-15T00:18:09.363 回答
2

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

于 2009-05-14T18:12:50.427 回答
2

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

于 2010-12-22T13:46:46.583 回答
0

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

于 2009-07-08T08:44:53.010 回答