[英]Boost::asio:: async_read() buffer corruption issue
我从chat_server的例子中获取了boost的代码。
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大小的char数组中。
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类中的上述函数启动与连接客户端的会话。
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 |
但是当从mem_opgs到结构stOrderPacket时,从read_msgs_.data读取的值以这样的方式接收:
a)第一个数据包是正确的
b)在第二个数据包中,前4个字节是垃圾值,然后我能够获得ID为3022的值,我才知道cz这个值被分配给stOrderPacket.MarketID。
c)可以从索引读取第三个值,该索引为0 + 2 * sizeof(int)
所以基本上对于每个收到的数据包,起始(n-1)* 4字节另外是垃圾优先然后信息开始。 对于所有3个数据包,bytes_transferred的值也是64。
注意:我在x86_64架构上的CentOS 7上运行此代码。
请帮助,如果有人可以。
在发送结构的原始数据时构建网络协议是不好的做法,也是非常不安全的。 结构内存在所有机器上都不完全相同,这可能导致错误。 一种简单的方法是使用序列化库从您的结构构建数据缓冲区,另一方面获取数据缓冲区并构建结构。 Boost Serialization是一个非常好的选择, Google Protocol Buffers也是如此。 这是一个例子:
SENDER
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);
缓冲区的大小将根据数据而有所不同,因此您需要在协议中添加大小传输。 这将包括序列化数据,然后告诉接收器期望的大小。 接收器然后将读取该大小,然后反序列化数据。
基于所描述的行为,其中应用程序协议使用固定大小的消息( 64
字节),并且当服务器读取消息时,消息n
的起始点偏移4 * (n - 1)
个字节,那么最可能的情况是客户端每个消息发送68
字节的数据,其中前64
个字节包含stOrderPacket
,客户端只需要每个消息64
个字节。 以下是一些需要检查的方面:
4
字节字段的较新版本,或者客户端正在使用在末尾添加4
字节字段的较新版本。 68
字节,则需要更新客户端或服务器以使用相同的应用程序协议。 另一方面,如果消息是64
字节,则服务器中可能存在错误(错误逻辑,未定义行为等)。 64
个字节,则验证服务器是否正在从套接字读取:
socket_
不是线程安全的,因此验证没有对它进行并发调用。 boost::asio::async_read()
的缓冲区( read_msg_.data()
)必须至少在调用完成处理程序之前保持有效。 async_read()
完成之前, async_read()
对socket_
执行其他读取操作。 此外,当使用标准布局结构来定义应用程序协议的任何部分时,可以发现通过在可能的情况下使用精确宽度类型和/或绘制协议来提高可读性和安全性:
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// 00 +-------+-------+-------+-------+-------+-------+-------+------+
// | ID |
// 04 +-------+-------+-------+-------+-------+-------+-------+------+
// | Market ID |
// 08 +-------+-------+-------+-------+-------+-------+-------+------+
// | Signal Name |
// / /
// 28 + ... +-------+-------+-------+------+
// | | Trade Symbol ... |
// 32 +-------+-------+-------+-------+ +
// / /
// 48 + ... +
// | |
// 52 +-------+-------+-------+-------+-------+-------+-------+------+
// | Quantity |
// 56 +-------+-------+-------+-------+-------+-------+-------+------+
// | Price |
// 60 +-------+-------+-------+-------+-------+-------+-------+------+
// | Transaction Type |
// 64 +-------+-------+-------+-------+-------+-------+-------+------+
struct stOrderPacket
{
int32_t ID;
int32_t MarketID;
char m_strSignalName[22];
char m_strTradeSymbol[22];
int32_t m_iQty;
float m_fPrice;
eTransactionType m_eTransactionType;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.