我已经从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大小的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上运行此代码。
请帮助,如果有人可以的话。
答案 0 :(得分:2)
在发送结构的原始数据时构建网络协议是不好的做法,也是非常不安全的。结构内存在所有机器上都不完全相同,这可能导致错误。一种简单的方法是使用序列化库从您的结构构建数据缓冲区,另一方面获取数据缓冲区并构建结构。 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());
RECEIVER
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);
缓冲区的大小会因数据而异,因此您需要在协议中添加大小传输。这将包括序列化数据,然后告诉接收器期望的大小。接收器然后将读取该大小,然后反序列化数据。
答案 1 :(得分:1)
基于描述的行为,其中应用程序协议使用固定大小的消息(64
字节),并且当服务器读取消息时,消息n
的起始点被{{1 }} bytes,那么最可能的情况是客户端每个消息发送4 * (n - 1)
个字节的数据,其中第一个68
个字节包含64
,而客户端只期望{每条消息{1}}个字节。以下是一些需要检查的方面:
stOrderPacket
字节字段的较新版本,或者客户端正在使用在最后添加64
字节字段的较新版本。4
字节,则需要更新客户端或服务器以使用相同的应用程序协议。另一方面,如果消息是4
个字节,那么服务器中可能存在错误(错误的逻辑,未定义的行为等)。68
个字节,请验证服务器是否正在从套接字中正确读取:
64
不是线程安全的,因此请确认没有对它进行并发调用。boost::asio::async_read()
的缓冲区(64
)必须至少在调用完成处理程序之前保持有效。socket_
完成之前,read_msg_.data()
尚未执行任何其他读取操作。此外,当使用标准布局结构来定义应用程序协议的任何部分时,可以发现通过在可能的情况下使用精确宽度类型和/或绘制协议来提高可读性和安全性:
socket_