c++中通过套接字实现数据
Data through Sockets in C++
我目前正在做一个使用网络的项目。我必须发送一个struct
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从一个套接字发送结构包到另一个套接字。我试过像这样发送struct
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));
}
甚至当客户端只是发送一个结构头数据是损坏的,当我读取它的服务器端为什么数据损坏了?
客户端发送循环
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());
}
server recv loop: (function call by select())
buff = new char[bav];
socket->read(buff, bav);
hexdump("buff", buff, bav);
插座->阅读():
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
所以,这是错误的,它肯定会导致错误。
buff = new char[bav];
socket->read(buff, bav);
hexdump("buff", buff, bav);
socket->read() :
int TcpSocket::read(char *buff, int len)
{
return recv(this->_socket, buff, len, 0);
}
不能忽略recv()
的返回值。
源自man 2 recv
:
那么,你收到了多少字节?如果你放弃recv()
的结果,这是不可能的。也许recv()
失败了,如果不检查返回值,您永远不会发现。也许它只填满了你的部分缓冲区。你必须检查recv()
的返回代码。这是人们在编写使用TCP的程序时犯的第一个错误。
你需要修改你的代码来处理以下情况:
recv()
调用可能会完全填满你的缓冲区recv()
调用可能会部分填满你的缓冲区recv()
调用可能返回0,表示发送方已经关闭连接recv()
调用可能是EINTR
,因为它被系统调用中断了。recv()
呼叫可能指示ECONNRESET
,因为发送方突然关闭连接或消失。recv()
呼叫可能遇到其他错误
记住:当使用TCP时,仅仅因为你send()
16个字节并不意味着另一个对等端也会recv()
16个字节——它可能被分解成块。TCP是一个流协议。与UDP不同,相邻的数据块可以任意地连接或分割。
-
每次只需要掩码低8位:
buffer[3] = (arg >> 24) & 0xff; buffer[2] = (arg >> 16) & 0xff; buffer[1] = (arg >> 8) & 0xff; buffer[0] = (arg) & 0xff;
-
反序列化
时也这样做
如果我是你,我就不会重新发明轮子。有很多文档完备且经过测试的库/协议可以满足你的需求。一个我突然想到的小清单:
- 提高序列化
- Google Protocol Buffers JSON XML>CORBA
- 如何实现高效的算法来计算大型数据集的多个不同值?
- 如何使用set实现无序数据结构?
- 如何知道用于实现标准代码段的确切数据结构和算法,例如在C++STL中?
- 如何在C++中实现节点数任意的通用树数据结构?
- 为 Sql 服务器实现 odbc 包装器.将数据库数据读取为字符或要求驱动程序将数据转换为 C 类型
- C++ 中的 TRIE 数据结构实现
- 如何有效地实现将向量的数据分配给多个变量?
- 如何实现共享数据的复制构造函数
- Trie数据结构的实现
- 实现具有浮点键的类似哈希表的数据结构,其中公差内的值被合并在一起
- 数据结构实现
- 对象内部有大量数据容器,实现更高效的对象交换
- 与shared_ptr相比,更小的运行时数据结构和更快的代码可实现独特的_ptr
- 如何实现数据结构,就像C 中的数组一样支持不同的类型元素
- 在我的软件中实现数据同步的服务
- 实现数据结构时的智能指针或原始指针
- 如何利用多态性实现数据本地化
- 将值映射到像素对-如何实现数据结构
- 如何使用c++库实现数据包整形或QOS
- c++中通过套接字实现数据