我想将recv
系统调用与非阻塞标志MSG_NONBLOCK一起使用。但是使用此标志,syscall可以在满足完整请求之前返回。所以,
答案 0 :(得分:4)
这就是我为同样的问题所做的,但我想要一些确认,这可以按预期工作......
ssize_t recv_allOrNothing(int socket_id, void *buffer, size_t buffer_len, bool block = false)
{
if(!block)
{
ssize_t bytes_received = recv(socket_id, buffer, buffer_len, MSG_DONTWAIT | MSG_PEEK);
if (bytes_received == -1)
return -1;
if ((size_t)bytes_received != buffer_len)
return 0;
}
return recv(socket_id, buffer, buffer_len, MSG_WAITALL);
}
答案 1 :(得分:3)
编辑:
Plain recv()将在调用时返回tcp缓冲区中所需的字节数。如果没有数据准备在套接字上读取,MSG_DONTWAIT只是避免阻塞。 MSG_WAITALL请求阻塞,直到可以读取所请求的整个字节数。所以你不会得到“全部或全部”行为。如果没有数据存在,你应该获得EAGAIN并阻塞,直到完整的消息可用为止。
您可以使用FIONREAD(如果您的系统支持它)来制作MSG_PEEK或ioctl()中的某些东西,它有效地表现得像您想要但我不知道如何使用recv()标志来实现目标
答案 2 :(得分:3)
对于至少在Linux上接收的IPv4 TCP,如果指定了MSG_NONBLOCK(或文件描述符设置为非阻塞),则忽略MSG_WAITALL。
来自Linux内核中net / ipv4 / tcp.c中的tcp_recvmsg():
if (copied >= target && !sk->sk_backlog.tail)
break;
if (copied) {
if (sk->sk_err ||
sk->sk_state == TCP_CLOSE ||
(sk->sk_shutdown & RCV_SHUTDOWN) ||
!timeo ||
signal_pending(current))
break;
如果指定了MSG_DONTWAIT,则此演员表中的目标设置为所请求的大小;如果不指定,则设置为较小的值(至少为1)。如果出现以下情况,该功能将完成:
对我而言,这似乎可能是Linux中的一个错误,但无论哪种方式,它都无法按照您想要的方式运行。它看起来像dec-vt100的解决方案,但是如果你尝试从多个进程或线程中的同一个套接字接收,则存在竞争条件。
即,另一个线程/进程的另一个recv()调用可以在你的线程执行一次窥视后发生,导致你的线程阻塞第二个recv()。