2011-05-13 58 views
10

使用C中的recv()函數從'流'套接字讀取len參數可以爲零嗎?長度爲零的recv()是否有效?

recv()函數對於'遠程連接關閉'返回零和正常操作中實際讀取的字節數,所以如果它應該讀取零字節聽起來有問題。

P.S.
是的,我知道單獨處理它,並沒有得到這種情況,我仍然想知道該功能是否可以處理它,我找不到任何有關它的文檔。

+3

你試過了嗎? – BlackBear 2011-05-13 16:21:40

+0

不確定爲什麼這是有問題的?當你要求它讀取0字節時,你期望read()返回什麼? 1? -1? – stijn 2011-05-13 16:26:27

+0

@BlackBear,還不如,如果有人知道構建一個測試,我寧願得到答案 - 即使最簡單的測試需要設置某些東西來連接,建立連接,然後嘗試看看會發生什麼。 – Eran 2011-05-13 16:33:56

回答

4

我相信答案是「取決於」。 如果它沒有被標準(並且實際上我相信它不是)規定的,任何實現都可以按照它的意願進行。

  • 它可能會失敗,EINVAL
  • 它可以掛
  • 它可以返回0,繼續
  • 它可以打印一個有趣的消息,並開始遊戲流氓(我的理解來做到這一點gcc: )))

其實在我的實現中,它返回0並繼續。要檢查它是否失敗或只是返回0,您可以在電話後檢查errno,因此它不像您想象的那樣有問題。

+2

我可以生活在「取決於」......謝謝。 – Eran 2011-05-13 16:49:44

+0

我的系統(Linux)上的文檔清楚地定義了'recv'的行爲方式,並且沒有任何關於阻止任何這種行爲的緩衝區長度爲零。我不明白爲什麼你認爲零是某種特殊的東西,並且某種程度上非常特殊,以至於所定義的行爲應該被忽略,所以我認爲你的答案是錯誤的。詳情請參閱我的回答。 – ikegami 2011-05-13 17:59:28

+0

正如我所說,我認爲這可能是一個問題,由於返回值,通常是因爲它很奇怪。我不知道,也不確定這是爲什麼我問。 – Eran 2011-05-13 18:30:03

-3

我不認爲長度參數可以是零,因爲即使是一個空字符串(消息)需要終止'\ 0'。

+2

來自套接字的「消息」不一定是以nul結尾的字符串。 – 2011-05-13 16:29:14

+1

...並不一定是一個字符串:-D – 2011-05-13 16:31:05

+0

好吧,我的壞。注意到了。儘管C語言允許,但我仍然認爲零字節緩衝區的概念值得商榷。 – 2011-05-13 18:10:38

1

我很確定它是未定義的......看着Linux它一直傳遞到「驅動程序」(即.tcp等),所以它可能意味着什麼,但我不認爲這是意義被很好地定義。當然,SuS並沒有對此做任何明確的說明。

我認爲你幾乎可以肯定不會這樣做,並且根據你想要做的事情使用帶有1字節或poll()的MSG_PEEK。

3

recv我的系統(Linux)的有關文檔說

如果沒有消息可在插座,接收呼叫等待消息的到達

如果消息是太長以至於無法裝入所提供的緩衝區中,取決於從中接收消息的套接字的類型,可能會丟棄多餘的字節。

根據文檔,我期望我的recv等待消息,然後有效地丟棄它(UDP)或將它留在流(TCP)中。

這可以用來測試一個非阻塞的TCP套接字是否有數據等待。

更新:測試顯示的文檔的這種解釋是正確的。

服務器:

$ perl -MIO::Socket::INET -E' 
    my $s = IO::Socket::INET->new(Listen => 1) or die $!; 
    say $s->sockport; 

    my $c = $s->accept or die $!; 
    say "[".localtime."] connected"; 

    $c->recv(my $buf, 0) // die $!; 
    say "[".localtime."] received"; 

    say <$c>; 
' 
39493 
[Fri May 13 13:49:53 2011] connected 
[Fri May 13 13:49:55 2011] received 
foo 

客戶:

$ perl -MIO::Socket::INET -E' 
    my $s = IO::Socket::INET->new(
     PeerAddr => "127.0.0.1", 
     PeerPort => $ARGV[0], 
    ) or die $!; 
    sleep 2; 
    say $s "foo"; 
' 39493 

(這些Perl函數只是瘦接口的系統調用隨意改寫他們在C.)

+0

雖然這可行,但是perl可以這樣做,但是C的實現不會呢?難道這個「精簡界面」也會用一些邊緣處理來包裝它。我感謝你的回答,但仍然覺得解釋「這取決於」是更準確的答案。什麼時候(以及如果有的話)我最終會自己測試一下,我可能會在這裏更新。 – Eran 2011-05-13 18:33:22

+0

@Xenorose,我去了* system *文檔('man recv'),而不是Perl的。如果您通過電子郵件發送給我([email protected]),我甚至會用我的答案替換Perl代碼。 – ikegami 2011-05-13 20:04:10

0

POSIX的頁面約recv()是不是很清楚它。在非標準部分(「應用程序使用」)中,如果沒有給出標誌,則說明在套接字上的recv()相當於read()。 POSIX的頁面read()表示讀取0字節可能會檢查錯誤;如果沒有錯誤或執行不檢查,則不會發生任何事情並返回0。

相關問題