I have taken the code from chat_server example of 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;
};
The stOrderPacket is the structure shared by TCP client and 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_;
};
The chat_message class is a class which holds the message to be written or read, and the data is stored in simply a char array of size equal to the size of structure 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()));
}
The above function in chat_session class starts a session with a connected client.
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()));
}
};
The packets which are being sent from client side are as follows:
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 |
But the values read from read_msgs_.data, when memcopied into structure stOrderPacket are received in such a way that:
a) The first packet is correct
b) In the second packet the first 4 bytes are garbage values and then I am able to get the value of ID as 3022, which I came to know cz this value got assigned to stOrderPacket.MarketID.
c) The Third value can be read correct from the index which is 0+2* sizeof(int)
So basically for every packet received, starting (n-1)*4 bytes are additionally are garbage first and then the information starts. Also the value of bytes_transferred is 64 for all the 3 packets.
Note: I am running this code on CentOS 7 on x86_64 architecture.
Please help, if anyone can.
It is bad practice and very unsafe to build a network protocol around sending the raw data of a structure. A structures memory is not the exact same on all machines and this can lead to errors. An easy way to accomplish this is to use a serialization library to build you a data buffer from your structure and on the other side take a data buffer and build the structure. Boost Serialization is a very good option and so is Google Protocol Buffers . Here is an example:
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);
The size of the buffer will vary depending on the data so you will need to add size transmission to your protocol. This will consist of serializing the data and then telling the receiver the size to expect. The receiver will then read for that size and then deserialize the data.
Based on the described behavior where the application protocol uses a fixed size message ( 64
bytes), and when the server reads a message, the starting point for message n
is offset by 4 * (n - 1)
bytes, then the most likely case is that the client is sending 68
bytes of data per message, where the first 64
bytes contain a stOrderPacket
, and the client is only expecting 64
bytes per message. Here are a few areas to check:
4
byte field from the end, or the client is using a newer version that added a 4
byte field to the end. 68
bytes, then the client or server need to be updated to use the same application protocol. On the other hand, if the message is 64
bytes, then the error likely exists within the server (bad logic, undefined behavior, etc.). 64
bytes per message, then verify that the server is properly reading from the socket:
socket_
is not thread safe so verify there are no concurrent calls being made to it. read_msg_.data()
) provided to boost::asio::async_read()
must remain valid at least until the completion handler is called. socket_
until async_read()
has completed. Also, when using a standard-layout struct to define any part of an application protocol, one may find that it increases readability and safety by using exact-width types where possible and/or diagraming the protocol:
// 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;
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.