2013-10-28 90 views
4

我有一個應用程序,其中各種實體通過套接字相互通信,我使用的是C編程語言。當一個實體向另一個實體發送一個長消息時,recv()函數可能會部分讀取該消息。因此,我必須通過附加所有收到的部分來重新構造收件人一方的消​​息。套接字編程:recv()

我的問題是關於recv()的一般插座編程問題。 recv()如何知道消息何時被完全讀取?我應該用一個特殊字符如「\ n」來終止郵件嗎?或者我應該將郵件的大小作爲標題發送?常用的做法是什麼?

回答

6

正如您已經注意到的,使用流套接字沒有內置的消息邊界概念。您需要構建一些確定應用程序級協議中的消息結束的方式。

你提出的兩個選項都是常見的:或者是一個長度前綴(用消息長度開始每個消息)或者是一個消息結束符(這可能只是一個基於文本的換行符協議,例如)。第三個較少使用的選項是爲每條消息指定一個固定大小。這些選項的組合也是可能的 - 例如,包含長度值的固定大小頭。

+0

謝謝......它真的有助於瞭解常見的做法。 – NewToAndroid

2

當您使用send()和recv()時,您指定一個緩衝區大小。

如果使用這樣的方式來發送消息:

send(new_socket,message,strlen(message),0); 

第三個參數是你的緩衝區的大小。

學習成功發送數據包的一種方法是如果您使用的是TCP套接字,則send()recv()將返回相同的值。您可以通過檢查郵件大小是否與從send()返回的值相同來檢查發件人。

爲了在接收端檢查,最簡單的方法是將字符串分隔符\0的末尾加到字符串中。

+0

爲了發送分隔符,'strlen(message)+ 1'將會非常好。 – glglgl

+0

除此之外,最好談談「發件人方」。從連接開始,雙方都可以發送和接收,所以使用術語「服務器」在這裏是非常具有誤導性的。 – glglgl

+0

@glglgl謝謝我將服務器和客戶端固定到發件人和收件人。 此外,我認爲字符串已經有\ 0分隔符,因此,這將已經包含在字符串的長度,但如果字符串沒有分隔符,那麼你是對的。 –

0

一旦開始在C語言中做大量的網絡編程之一就很快實現爲什麼更高層次的語言流行起來!基本上他們有很多內置的功能,你很快就會發現自己希望C提供更多的功能!

首先我強烈建議你看看ZeroMQ(http://zeromq.org/bindings:c)及其C綁定。這在處理連接,消息分界等方面爲你做了很多可怕的驢工作。另外,它在運行時很快;快速開發並快速運行,這是一個好的圖書館的標誌。

ZeroMQ接近完美的套接字庫。它唯一沒有做的事情(AFAIK)主動監視連接,看看它是否崩潰 - 你只會發現是否嘗試發送一些東西。如果您想檢查連接的健康狀況,則必須定期發送自己的連接測試消息。

其次,我會鼓勵你考慮序列化。一旦你開始擁有指向分配內存的複雜數據結構,你將開始進入複雜而困難的領域。當面對這個問題時,我選擇使用ASN.1來使用Objective Systems的庫和工具(http://www.obj-sys.com/index.php)定義和序列化我的數據結構。它花錢,需要一點習慣,但我發現它在節省開發時間方面非常有價值。

以及序列化例程,他們給你一些非常方便的演員,C不提供。例如,他們的代碼生成器將爲您提供複製數據類型的例程,如果該數據類型是一個充滿指向分配內存的指針的結構,那麼它非常方便。

這裏可能有一些免費的工具和庫。 Google的協議緩衝區有一個C綁定(http://code.google.com/p/protobuf-c/),這是一個很好的選擇。