2010-05-31 105 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()。