【发布时间】:2012-12-13 06:23:48
【问题描述】:
我目前正在做一个使用网络的项目。我必须发送一个结构
struct Header
{
uint32_t magic;
uint32_t checksum;
uint32_t timestamp;
uint16_t commandId;
uint16_t dataSize;
};
struct Packet
{
struct Header header;
char data[128];
};
我正在尝试使用 TCP 将结构数据包从一个套接字发送到另一个套接字。我试图像这样发送我的结构
send(socket, &my_struct, sizeof(my_struct), 0);
但它不起作用,所以我尝试将我的结构序列化为 char*
unsigned char *Serialization::serialize_uint32(unsigned char *buffer, uint32_t arg)
{
buffer[3] = (arg >> 24);
buffer[2] = (arg >> 16);
buffer[1] = (arg >> 8);
buffer[0] = (arg);
return (buffer + sizeof(uint32_t));
}
unsigned char *Serialization::serialize_uint16(unsigned char *buffer, uint16_t arg)
{
buffer[1] = (arg >> 8);
buffer[0] = (arg);
return (buffer + sizeof(uint16_t));
}
unsigned char *Serialization::deserialize_uint32(unsigned char *buffer, uint32_t *arg)
{
memcpy((char*)arg, buffer, sizeof(uint32_t));
return (buffer + sizeof(uint32_t));
}
unsigned char *Serialization::deserialize_uint16(unsigned char *buffer, uint16_t *arg)
{
memcpy((char*)arg, buffer, sizeof(uint16_t));
return (buffer + sizeof(uint16_t));
}
即使客户端简单地发送一个 struct 标头数据在我读取服务器端时也已损坏 为什么数据损坏?
客户端发送循环
TcpSocket tcp;
Packet p;
std::stringstream ss;
int cpt = 0;
int ret = 0;
char *serialized;
tcp.connectSocket("127.0.0.1", 4242);
while (getchar())
{
ss.str("");
ss.clear();
ss << cpt++;
p.header.magic = 0;
p.header.checksum = 1;
p.header.timestamp = 2;
p.header.commandId = 3;
p.header.dataSize = ss.str().length();
memset(p.data, 0, 128);
memcpy(p.data, ss.str().c_str(), ss.str().length());
serialized = new char[sizeof(Header) + ss.str().length()];
bzero(serialized, sizeof(Header) + ss.str().length());
Serialization::serialize_packet(serialized, p);
hexDump("serialized", serialized+1, sizeof(Header) + ss.str().length());
ret = tcp.write(serialized+1, sizeof(Header) + ss.str().length());
}
服务器接收循环:(由 select() 调用的函数)
buff = new char[bav];
socket->read(buff, bav);
hexdump("buff", buff, bav);
socket->read() :
int TcpSocket::read(char *buff, int len)
{
int ret;
ret = recv(this->_socket, buff, len, 0);
return (ret);
}
当我运行这些程序时:
./server
[Server] new connexion :: [5]
recv returns : 17
buff serialized:
0000 00 00 00 00 14 00 00 00 1c 00 00 00 1a 00 00 00 ................
0010 1b
./client
serialized data:
0000 00 00 00 00 00 00 01 00 00 00 02 00 03 00 01 30 ...............0
0010 00
send returns : 17
【问题讨论】:
-
我们是否假设客户端正在以适当的反向算法解包(请注意,您应该使用
unsigned char作为打包缓冲区)。此外,您在第一种情况下的结构包装以及机器端格式 将发挥作用。 -
对于 uint16 和 uint32,您可以只使用 ntohl、ntohs、htonl 和 htons。简短的回答是:您必须在字节级别精确定义数据格式,并在发送和接收时正确转换为“有线格式”。
-
@DavidSchwartz 我同意,但是当我几天前提出这个作为解决类似问题的解决方案时,我立刻被一边跳一边跳,因为它不在“标准”。仍然被那个刺痛。(顺便说一句,我仍然会使用 POSIX 函数来做这件事,就像你可能会做的那样)。
-
有两个明显的问题。首先, send(socket, &my_struct, sizeof(my_struct)) 将不起作用,因为 send() 需要 四个 参数。其次,序列化应该使用无符号字符(即“字节”)而不是字符。正如已经指出的那样,消除字节序问题的“网络”功能甚至更好。
-
@WhozCraig:由于这个问题被标记为
C和C++并使用uint32_t,我无法想象“标准”会是什么。 :)
标签: c++ c sockets serialization tcp