2011-06-05 52 views
3

我目前有一個基本的客戶端/服務器設置。服務器需要從客戶端獲取請求並需要響應不同的請求消息類型。客戶端請求的一個例子可能是獲取可用文件列表,還有多少其他客戶端連接到服務器等。這在C/C++套接字通信中是否合理?

我顯然必須找出一種方法來確定從接收到的消息中的消息類型發件人。我想知道,如果我有一個用必要數據定義的結構,那麼我是否可以將結構強制轉換爲void *,通過發送(sockfd,message,length,flags)系統調用,並在接收端進行發送回到結構。這當然假定我在同一個環境中運行客戶端和服務器。

舉例來說,如果我有以下結構:

struct message { 
    enum messageType { GET_FILES, GET_CLINET_NUMBER} messageType, 
} 

,並使用該結構以如下方式

struct message msg; 
msg.messageType = GET_FILES; 
send(server_sockfd, (void*)&msg, sizeof(struct), 0) 

,並在接收器上發送消息,

recv(,msg_buffer); 
struct message received = (struct message*)msg_buffer; 

忽略這些小的語法問題,任何人都可以建議這個方案是否可行?如果沒有,是否有任何其他方式來傳遞消息而不發送原始char *?

回答

4

這是完全可能的。不過,不建議這樣做,因爲現在你爲客戶端和服務器使用了相同的環境,但將來可能會更改,並且必須將此代碼更改爲更獨立於平臺/實現。

選項? boost :: serialization,XML-RPC,甚至HTTP/REST或任何其他適合您的高級協議,Google協議緩衝區,CORBA等。

1

有兩點需要注意:

  1. Endianness。如果你的客戶端和服務器的排列順序各有差異,那麼你將處於無法通信的狀態。鑑於今天對x86系統的高度重視,您可能會說服自己對此限制感到滿意。如果我是你,我至少會建立一個驗證。例如,在每個通信會話開始時發送一個已知的校驗和,例如0xdeadbeef。這將允許您聲明客戶端和服務器之間的字節序相同,希望避免會話的繼續和各種潛在的錯誤。

  2. Word Size。這是你爲什麼不應該做你想做的事情的更陰險和更強大的原因。除非你強烈斷言發送者和接收者的字數永遠不會不同,否則你的方法充滿了危險。考慮你有一個結構如下:

    struct some_msg { long payload; };

    當32位的gcc/linux系統發送該消息給一個gcc/Linux 64位系統,會發生什麼?那麼,在32位系統上,它將愉快地發送4個字節的數據。但是,64位系統會將結構覆蓋到8個字節的數據上。壞消息是熊。

儘管從x86轉換到sparc可能不太可能,但隨着時間的推移,系統將會變爲64位。不管你有沒有傳統的32位系統,我都不知道,但是對於客戶端和服務器都沒有嚴格的控制,它幾乎可以保證你將擁有一個混合字大小的環境。

如果您非常明確地定義和控制正在使用的平臺,我相信它可以工作。此外,您可以通過使用固定大小的類型定義(如int32_tuint64_t)來限制風險。如果你這樣做,你正在玩火,海事組織。任何可想象的優勢都可以通過將您的設計高度鎖定到系統中而迅速降低。

+0

另一個,甚至可能更糟的問題:填充字節。 C++編譯器有時會在結構的成員之間添加'不可見'填充字節,以便爲目標CPU提高內存訪問效率。填充不是標準化的,所以它可以在一個編譯器和另一個編譯器之間,或者在同一個編譯器的兩個版本之間,甚至在來自同一個編譯器版本的構建之間(特別是如果它們使用不同的優化級別構建時)不同地完成。因此,除非連接的兩端都運行完全相同的可執行二進制文件,否則事情可能會中斷。 – 2011-06-05 18:35:48

+0

對齊在給定的ISA ABI上是標準化的,並且在任何實字機器上,填充是對齊所需的最小值。而且,對於真實世界機器上的幾乎所有類型,對齊都是類型的大小。對齊必須總是*均勻地分割*類型的大小(由於C數組表示語義),所以如果設計的結構是這樣的,那麼在沒有填充的情況下,每個元素將以其大小的倍數開始,那麼你可以基本確定沒有填充。 – 2011-06-05 18:52:55

0

'可以將結構強制轉換爲void *,通過發送(sockfd,message,length,flags)系統調用,並且在接收端將其轉發回結構' - 參見迭戈的答案。請注意,如果在流中插入/刪除/更改了一個額外的隨機字節,則無法恢復或更糟糕的任何協議實際上會使服務器崩潰,但安全性不足,無法通過TCP傳輸。

'如果不是,有沒有其他的方式來傳遞消息而不發送原始字符*?'一個協議的唯一替代方案是可以可靠地,合理地重新組合來自一個字節(八位字節),strean的消息,即在每條消息之後斷開/重新連接以便終止流。這個方案的性能/延遲正是你所期望的 - 真的很差。

RGDS, 馬丁