Here's a simplified version of some code I'm working on:
这是我正在研究的一些代码的简化版本:
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);
}
If we assume that the first call to recv succeeds, returning a value between 1 and 32, is it safe to assume that the second call will also succeed? Can ret2 ever be less than ret1? In which cases?
如果我们假设第一次调用recv成功,返回1到32之间的值,是否可以安全地假设第二次调用也会成功? ret2能否小于ret1?在哪些情况下?
(For clarity's sake, assume that there are no other error conditions during the second call to recv: that no signal is delivered, that it won't set ENOMEM, etc. Also assume that no other threads will look at fd.
(为了清楚起见,假设在第二次调用recv期间没有其他错误条件:没有传递信号,它不会设置ENOMEM等。还假设没有其他线程会查看fd。
I'm on Linux, but MSG_DONTWAIT is, I believe, the only Linux-specific thing here. Assume that the right fnctl was set previously on other platforms.)
我在Linux上,但我相信MSG_DONTWAIT是这里唯一的Linux特有的东西。假设之前在其他平台上设置了正确的fnctl。)
5 个解决方案
#1
7
The POSIX standard specifies that with MSG_PEEK, "the data is treated as unread and the next recv() or similar function will still return this data." That seems to mean that unless ret2 is -1, it will be the same as ret1.
POSIX标准指定使用MSG_PEEK,“数据被视为未读,下一个recv()或类似函数仍将返回此数据。”这似乎意味着除非ret2为-1,否则它将与ret1相同。
#2
5
You must also consider the possibility that a different recv call, on a different thread, might be called between ret1 and ret2. That other call would get your data, leaving ret2 to end up with no data, or unexpectedly less data.
您还必须考虑在ret1和ret2之间调用不同线程上的不同recv调用的可能性。另一个调用将获取您的数据,使Ret2最终没有数据,或意外地减少数据。
If your app isn't multi-threaded, or is designed so that the fd is only used by these two calls, then you can ignore this. But if this is a risk, then you should put the two calls inside a locking mechanism.
如果您的应用程序不是多线程的,或者设计为只有这两个调用使用fd,那么您可以忽略它。但如果这是一个风险,那么你应该把两个调用放在一个锁定机制中。
#3
2
Your second call to recv() without MSG_PEEK can fail with EINTR or return incomplete data because it has been interrupted by a signal.
您对没有MSG_PEEK的recv()的第二次调用可能会因EINTR而失败或返回不完整的数据,因为它已被信号中断。
#4
1
I'm not sure about EAGAIN, but think that EBADF or ECONNRESET are possible.
我不确定EAGAIN,但认为EBADF或ECONNRESET是可能的。
#5
0
For your simple case, the subsequent recv will return ret1 number of bytes (if ret1 was not an error). However, for Multi-threaded design, it may not always be true.
对于您的简单情况,后续的recv将返回ret1个字节数(如果ret1不是错误)。但是,对于多线程设计,它可能并非总是如此。
#1
7
The POSIX standard specifies that with MSG_PEEK, "the data is treated as unread and the next recv() or similar function will still return this data." That seems to mean that unless ret2 is -1, it will be the same as ret1.
POSIX标准指定使用MSG_PEEK,“数据被视为未读,下一个recv()或类似函数仍将返回此数据。”这似乎意味着除非ret2为-1,否则它将与ret1相同。
#2
5
You must also consider the possibility that a different recv call, on a different thread, might be called between ret1 and ret2. That other call would get your data, leaving ret2 to end up with no data, or unexpectedly less data.
您还必须考虑在ret1和ret2之间调用不同线程上的不同recv调用的可能性。另一个调用将获取您的数据,使Ret2最终没有数据,或意外地减少数据。
If your app isn't multi-threaded, or is designed so that the fd is only used by these two calls, then you can ignore this. But if this is a risk, then you should put the two calls inside a locking mechanism.
如果您的应用程序不是多线程的,或者设计为只有这两个调用使用fd,那么您可以忽略它。但如果这是一个风险,那么你应该把两个调用放在一个锁定机制中。
#3
2
Your second call to recv() without MSG_PEEK can fail with EINTR or return incomplete data because it has been interrupted by a signal.
您对没有MSG_PEEK的recv()的第二次调用可能会因EINTR而失败或返回不完整的数据,因为它已被信号中断。
#4
1
I'm not sure about EAGAIN, but think that EBADF or ECONNRESET are possible.
我不确定EAGAIN,但认为EBADF或ECONNRESET是可能的。
#5
0
For your simple case, the subsequent recv will return ret1 number of bytes (if ret1 was not an error). However, for Multi-threaded design, it may not always be true.
对于您的简单情况,后续的recv将返回ret1个字节数(如果ret1不是错误)。但是,对于多线程设计,它可能并非总是如此。