2011-03-28 76 views
5

我已經閱讀了BG的網絡編程入門,但一個主題仍然有問題:數據封裝。
基本上我創建了一個包含數據長度和消息的結構。例如:數據封裝(網絡編程)

struct Data 
{ 
    int length; 
    std::string message; 
} 

如何發送?使用send()函數,我只能發送char *類型的變量。
另外,當我發送它時,在服務器端,我應該創建一個由封裝指定的長度的動態緩衝區並將消息打包到它?

+1

您絆倒的主題是「序列化」,而不是封裝。 – tenfour 2011-03-28 16:19:28

+0

+1對如何做到這一點的C++方式很好奇。你也應該問你是否需要擔心endian問題。 – Jeff 2011-03-28 20:57:33

回答

2

C++中的常用方法是提供可以將自定義類型序列化爲'流'對象的函數,然後提供一種獲取指向流中累積的數據塊開始的指針的方法。

的一個簡單的例子是的std :: ostringstream,您可以使用數據序列化爲流,然後獲得一個指向構造的字符串:

int i = 13; 
std::string message = "Hi"; 
std::ostringstream stream; 
stream << i << message; 

cout << stream.str() << endl; // prints "13Hi"; 

你可以爲你的Data類型做同樣的通過在提供<<>>運營商的適當的過載,如:

std::ostringstream &operator<<(std::ostringstream &stream, const Data &v) { 
    return stream << v.length << v.message; 
} 

std::ostringstream &operator>>(std::ostringstream &stream, Data &v) { 
    return stream >> v.length; >> v.message; 
} 

使用這些功能,你可以這樣做:

Data myData = { 13, "Hello" }; 

std::ostringstream stream; 
stream << myData; 

const std::string serializedData = stream.str(); 
send(.., serializedData.c_str(), serializedData.size() + 1, ..); 

在接收大小,你可以將數據讀入緩衝區,然後使用std::istringstream對象再次提取數據:

const char receivedData[ 1024 ]; 
// fill receivedData array using recv() 

std::string s = receivedData; 
std::istringstream stream(s); 
Data myData; 
stream >> myData; 

您可能需要緩衝所接收的數據位,直到從閱讀該流成功。

+0

我有點困惑。 'myData'有一個'c_str()'方法? – Jeff 2011-03-28 20:55:30

+0

@Jeff:對不起,我忘了從流中提取'std :: string'對象。我只是修正了這個例子。 – 2011-03-29 07:21:04

+0

+1現在有意義。謝謝! – Jeff 2011-03-29 17:04:52

0

Send()使用char *來允許以一個字節的倍數發送任何二進制數據。你有沒有嘗試鑄造到char *?

在接收端,你必須解開前幾個字節才能發現長度。當然,這種方法假定發送者和接收者使用相同長度的整數。您還應該小心發送給編譯器的打包參數。