以下是我正在处理的一些代码的简化版本:
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。)
答案 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不是错误)。但是,对于多线程设计,它可能并非总是如此。