2009-11-17 135 views
1

套接字編程的新手。有幾個問題:關於send/recv的問題

我的程序真的與它的輸出不一致。有時我的客戶收到,有時它沒有收到。我每次都使用相同的輸入。

  1. 只需要確認:可以在字節接待人數少於從服務器發送的字節數?

  2. 我該如何讓它停止接收一次我擁有所有需要的字節?

  3. 有沒有一種方法讓客戶知道它將「接收」多少字節,以便我可以將recv置於while循環中?

感謝大家的時間:)在C++ /非阻塞的情況下做到這一點,如果這很重要的話。

回答

3
  1. 假設這是TCP(不UDP),你能想到的插座作爲字節流。發件人可以以任何方式將他們置於想要的位置,並且您可以以任何方式將其取出想要的。因此,發件人可以在一次調用中寫入1k塊,並且如果需要,您可以一次接收一個字節。

  2. 有多種方式,但這裏有兩個很簡單的:

    • 如果發件人發送的所有數據後,關閉套接字,接收器將接收所有發送的數據,以及接下來的recv調用將返回0,表示沒有其他東西可以接收。這就是HTTP/1.0的工作原理。
    • 您可以更改協議以發送包含您要發送的數據長度的某種標頭,然後recv將知道需要多少字節。使用Content-length頭部,這就是HTTP/1.1的工作原理(大部分情況)。
  3. 你可以使用select來告訴你是否有任何東西,雖然它不告訴你多少。參見問題2.

2

用的recv()和非阻塞系統會給你,當你撥打電話(高達您提供緩衝區的大小),無論是當前可用的字節數。因此,如果你的發送者例如發送4K,這將在IP流上被分解成更小的分組,並且如果你對recv()的調用在第一個分組到達時發生,你只會得到(剩下的數據將在幾毫秒或幾秒後到達,具體取決於網絡的延遲)。隨後對recv()的調用將不會獲得任何數據,部分或全部數據(取決於網絡時間,緩衝等)。

另外(非阻塞IO)recv()可以返回一個rc的EAGAIN,這意味着此時沒有數據可用。在這種情況下,通常使用select()方法等待某個可用的對象,然後再次調用recv()。

也可以幫助是什麼這一呼籲:

int err, avail= 0; 
err= soioctl(skt FIONREAD, (char*)&avail); 

此調用檢查前期多少字節可用於讀取,所以當你隨後調用的recv()將會爲您獻上至少該字節數(假設您提供給recv()的緩衝區足夠大)。

關於如何停止你的問題:

與通過IP數據流

通常情況下,有一種方法來告訴該消息是否完整。例如。與許多RFC通信(例如與郵件服務器或http服務器交談)命令以\ n結尾,因此如果您收到數據並且其中沒有\ n,則您繼續閱讀,因爲應該有更多。

在其他形式中,數據的開始會告訴你有多少數據會跟隨。 HTTP請求的頭部具有大小字段,或者通過SOCKS代理進行連接時,請求和返回數據包已定義長度。在這樣的情況下,你可以循環,直到你有這個數量的數據(或直到連接失敗)。

但是,這實際上是一個在流上定義協議的問題,即發送者和接收者必須就數據的發送方式建立某種協議。一個IMAP服務器讀取\ n命令並處理它們,打印服務器可能會讀取所有數據,直到連接終止(recv()失敗,並且另一個協議可能只是前兩個字節作爲長度字段接下來會有多少數據。