我想使用带有非阻塞标志的recv syscall MSG_NONBLOCK。但是有了这个标志,syscall可以在完全满足请求之前返回。所以,
将阻塞recv重写到循环中?
发布于 2013-06-11 15:23:12
至少对于Linux上的IPv4 TCP来说,如果指定了MSG_NONBLOCK (或者文件描述符设置为非阻塞),那么MSG_NONBLOCK就会被忽略。
来自Linux内核中net/ipv4 4/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)。该功能将在下列情况下完成:
已经复制了足够多的字节,有一个套接字错误的non-blocking)
G 212)
在我看来,这似乎是Linux中的一个bug,但无论是哪种方式,它都无法按您所希望的方式工作。看起来,dec- It 100的解决方案是可以的,但是如果您尝试在多个进程或线程中从同一个套接字接收,则存在一个争用条件。
也就是说,在线程执行了peek之后,另一个线程/进程可能会调用另一个recv(),从而导致线程阻塞第二个recv()。
发布于 2010-05-31 12:59:24
编辑:
平原recv()将在调用时返回tcp缓冲区中的任何内容,最多返回所请求的字节数。如果没有任何数据可以在套接字上读取,MSG_DONTWAIT就可以避免阻塞。MSG_WAITALL请求阻塞,直到可以读取所请求的全部字节。这样你就不会有“全部或没有”的行为。充其量,您应该获得EAGAIN,如果没有数据,并阻塞,直到完整的消息是可用的,否则。
您可能可以使用FIONREAD (如果您的系统支持的话)在MSG_PEEK或ioctl()中设计一些可以有效地按照您的需要运行的东西,但我不知道如何使用recv()标志来实现您的目标。
发布于 2011-06-07 21:10:30
这就是我对同样的问题所做的,但我想确认一下,这件事和预期的一样.
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);
}https://stackoverflow.com/questions/2943434
复制相似问题