您不能只是“发送”您的课程。您必须在您的班级中发送数据的表示。并且向您的班级发送指针也不起作用。当网络上的另一个应用程序收到您的指针时,它对他们来说将毫无意义。
考虑一下:
class Data
{
std::string name_;
unsigned value_;
} data;
您不能只是“发送课程”。如果您尝试执行以下操作:
send(&data, sizeof(data));
...您最终将向下游客户端发送废话。 value_
可能会被正确接收,但name_
肯定不会。这是因为std::string
对象不仅仅包含构成字符串的字符。还有计数器,指向数据缓冲区的指针,还有谁知道还有什么。字符本身可能甚至不会出现在所指示的内存空间中(&data, &data[sizeof(data)])
——这些字符将完全在其他地方。因此,使用send
上面的伪代码,您不仅发送了一堆客户无法理解的内容,而且很多时候您甚至不发送他们可以理解的内容。
输入序列化。序列化只是意味着创建可以存储、保存或发送到某个地方并在以后重新组合的数据对象的表示。您决定此序列化将采用何种形式。在上述情况下data
,我们可能决定像这样进行序列化:
NNNNCCCCCCCC...VVVV
其中每个字符为 1 个字节,并且:
- N 是一个 4 字符整数,是
name_
ASCII 表示的字符数
- C 是 N 个字节,每个字节是一个字符
name_
- V 是一个 4 字符的无符号整数,是
value_
ASCII 表示的值
上面序列化和发送的一种方法data
可能是这样的(警告:不是生产质量,未经测试):
stringstream ss;
ss
<< setw(4) << setfill('0') << right << data.name_.length() << setw(0)
<< data.name_
<< setw(4) << data.value_;
string buf = ss.str();
send(buf.c_str(), buf.length());
现在,我们不是尝试发送data
,而是发送一个代表 的字符串data
。如果data
是这样创建的:
data.name_ = "foo";
data.value_ = 42;
...然后通过套接字发送的字符串将是:
0003foo0042
这可以由客户端接收并重新组合到Data
客户端的新对象中,该对象模仿您在服务器端的内容。
我们上面使用的映射--NNNNCCCCCCCC...VVVV
双方都必须理解。这通常被称为通信协议。
所有应用程序领域都使用了无数的协议和序列化方法。它们的范围从超级简单的,如我上面概述的,到高度压缩和复杂的,如FIX/FAST。许多库提供满足广泛应用需求的序列化功能。 Boost.Serialization 浮现在脑海中,我建议您考虑一下。
我已经在这里掩盖了更多内容。诸如字节序、安全性、会话控制之类的东西……如果您要进行任何重要的网络编程,无论是在客户端还是服务器端,您都需要学习很多东西。