【问题标题】:Encapsulation of data (Network programming)数据封装(网络编程)
【发布时间】:2011-03-28 15:19:50
【问题描述】:

我已阅读 BG 的《网络编程简介》,但有一个主题仍然存在问题:数据封装。
基本上我创建了一个包含数据长度和消息的结构。例如:

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

如何发送?使用send() 函数,我只能发送 char* 类型的变量。
另外,当我在服务器端发送它时,我是否应该创建一个由封装指定长度的动态缓冲区并将消息打包到其中?

【问题讨论】:

  • 你绊倒的话题是“序列化”,而不是封装。
  • +1 很好奇如何以 C++ 方式做到这一点。您还应该询问是否需要担心字节序问题。

标签: c++ serialization network-programming encapsulation


【解决方案1】:

C++ 中的常用方法是提供可以将自定义类型序列化为“流”对象的函数,然后提供一种方法来获取指向流中累积的数据块开头的指针。

一个简单的例子是 std::ostringstream ,您可以使用它来将数据序列化为流,然后获取指向构造字符串的指针:

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

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

您可以通过提供&lt;&lt;&gt;&gt; 运算符的适当重载来对您的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;

您可能需要稍微缓冲接收到的数据,直到从流中读取成功。

【讨论】:

  • 我有点困惑。 myDatac_str() 方法?
  • @Jeff:抱歉,我忘了从流中提取std::string 对象。我刚刚修复了这个例子。
【解决方案2】:

Send() 接受一个 char* 以允许以一个字节的倍数发送任何二进制数据。您是否尝试过强制转换为 char*?

在接收端,您必须解压缩前几个字节才能发现长度。当然,这种方法假设发送者和接收者使用相同长度的整数。您还应该小心发送给编译器的打包参数。

【讨论】:

    猜你喜欢
    • 2022-06-11
    • 1970-01-01
    • 1970-01-01
    • 2017-04-28
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-30
    相关资源
    最近更新 更多