2010-05-31 104 views
7

我想用recv带非阻塞标志MSG_NONBLOCK的系统调用。但有了这个标志,系统调用可以在全部请求满足之前返回。所以,recv with MSG_NONBLOCK and MSG_WAITALL

  • 我可以添加MSG_WAITALL标志吗?它会不会阻塞?
  • 或如何应该重写阻止的recv与非阻塞的recv循环
+0

猜测你想要腾出用户进程的内存(缓冲不完整的消息),所以你希望使用内核内存。我怀疑它会起作用。 – 2018-02-17 20:42:36

回答

3

编辑:

平原的recv()将返回无论是在TCP缓冲区的调用达到所要求的时间字节数。 MSG_DONTWAIT只是在没有数据准备在套接字上读取时避免阻塞。 MSG_WAITALL请求阻塞,直到读取所请求的全部字节数。所以你不会得到“全部或没有”的行为。充其量,如果没有数据存在,最好应该得到EAGAIN,并阻止直到完整的消息可用。您可以使用FIONREAD(如果您的系统支持它)将MSG_PEEK或ioctl()中的某些东西设计为有效行为,但我不知道如何使用recv()来实现您的目标。标志。

+1

NONBLOCK只能返回所需消息的一部分。我想要得到EAGAIN表格非阻塞recv,如果它只想返回部分味精。所以,我希望非阻塞recv与“全部或全部”行为 – osgx 2010-05-31 13:16:04

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); 
} 
2

对于IPv4 TCP至少在Linux上接收,MSG_WAITALL是,如果MSG_NONBLOCK忽略被指定(或者文件描述符被设置为非阻塞)。

从在Linux内核中的净/的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)否则。该函数将完成,如果:

  1. 足够的字节已经复制
  2. 有一个套接字错误
  3. 套接字已关闭或停产
  4. Timeo酒店为0(套接字设置为非阻塞)
  5. 有用于过程

对我来说,这似乎是它可以是Linux的一个bug未决的信号,但无论哪种方式,它不会工作,你所希望的方式。它看起来像dec-vt100的解决方案,但如果你尝试从多个进程或线程中的同一个套接字接收到竞争条件。
也就是说,另一个线程/进程调用另一个recv()可能会在线程执行一次查看后导致线程阻塞第二个recv()。