我从 boost 的 chat_server 示例中获取了代码。
enum eTransactionType{
eBuy=0,
eSell=1
};
struct stOrderPacket{
int ID;
int MarketID;
char m_strSignalName[22];
char m_strTradeSymbol[22];
int m_iQty;
float m_fPrice;
eTransactionType m_eTransactionType;
};
stOrderPacket 是 TCP 客户端和 TCPServer 共享的结构。
class chat_message
{
public:
enum { max_body_length = sizeof(stOrderPacket) };
chat_message()
: body_length_(0)
{
}
const char* data() const
{
return data_;
}
char* data()
{
return data_;
}
size_t length() const
{
return body_length_;
}
void SetData(char* msg, int len)
{
memset(data_,0x00,len);memcpy(data_,msg,len);
}
void SetOrderParams(stOrderPacket a_stOrderParams);
size_t body_length() const
{
return body_length_;
}
void ClearPacket()
{
memset(data_,0x00,max_body_length);
}
void body_length(size_t length);
private:
char data_[sizeof(stOrderPacket)];
size_t body_length_;
};
chat_message 类是保存要写入或读取的消息的类,数据存储在大小等于结构 stOrderPacket 大小的简单字符数组中。
class chat_session{
void start()
{
boost::asio::async_read(socket_,boost::asio::buffer(read_msg_.data(),sizeof(stOrderPacket)),
boost::bind(&chat_session::handle_read_body,shared_from_this(),placeholders::error, placeholders::bytes_transferred()));
}
chat_session 类中的上述函数启动与已连接客户端的 session 。
void handle_read_body(const boost::system::error_code& error,std::size_t bytes_transferred)
{
if (0!=error)
{
// handle Close connection.
return;
}
/// stub for parsing the packet
memcpy(&m_stOrderPacket,&m_pvBuffer,sizeof(m_stOrderPacket));
read_msg_.ClearPacket();
boost::asio::async_read(
socket_, buffer(read_msg_.data(),sizeof(structs::stOrderParameters)),
boost::bind(&chat_session::handle_read_body,shared_from_this(),placeholders::error,placeholders::bytes_transferred()));
}
};
从客户端发送的数据包如下:
ID | MarketID | Symbol | SignalName | TradeType | Qty | EntryPrice |
| 3021 | 1030320 | RELIANCEEQ | MU_30_INLE_4097_3 | Long | 285 | 1121.1 |
| 3022 | 1030321 | RELIANCEEQ | MU_30_INLE_4097_3 | Long | 178 | 1121 |
| 3038 | 1030505 | RELIANCEEQ | AS_15_SE_53 | Short | 340
| 1116.95 |
但是从 read_msgs_.data 读取的值,当 memcopied 到结构 stOrderPacket 中时,以这样的方式接收:
a) 第一个数据包正确
b) 在第二个数据包中,前 4 个字节是垃圾值,然后我能够获得 ID 的值 3022,我开始知道这个值已分配给 stOrderPacket.MarketID。
c) 可以从索引中正确读取第三个值,即0+2* sizeof(int)
所以基本上对于每个接收到的数据包,开始的 (n-1)*4 个字节首先是垃圾,然后是数据开始。 对于所有 3 个数据包,bytes_transferred 的值也是 64。
注意:我在 x86_64 架构的 CentOS 7 上运行这段代码。
请帮助,如果有人可以。
最佳答案
围绕发送结构的原始数据构建网络协议(protocol)是一种不好的做法,而且非常不安全。结构内存在所有机器上并不完全相同,这可能会导致错误。实现此目的的一种简单方法是使用序列化库从结构中为您构建数据缓冲区,另一方面获取数据缓冲区并构建结构。 Boost Serialization是一个很好的选择,Google Protocol Buffers 也是如此。 .这是一个例子:
发件人
std::vector<unsigned char> buffer;
stOrderPacket packet;
Serialize(packet, buffer);
boost::asio::write(socket, boost::asio::buffer(buffer), boost::asio::transfer_all());
接收者
std::vector<unsigned char> buffer;
buffer.resize(buffer_size);
stOrderPacket packet;
boost::asio::read(socket, boost::asio::buffer(buffer), boost::asio::transfer_exactly(buffer_size));
Deserialize(packet, buffer);
缓冲区的大小会因数据而异,因此您需要将大小传输添加到您的协议(protocol)中。这将包括序列化数据,然后告诉接收者期望的大小。然后接收器将读取该大小,然后反序列化数据。
关于c++ - Boost::asio::async_read() 缓冲区损坏问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30391097/