I’m currently working on a small project: there’s a protocol for sending some strings via UDP implemented with standard C interface.
Although it works pretty fine, I’d like to rewrite it with some more sophisticated C++ (consider it exercise).
Currently it’s something like that: A client wants that string so it sends the following struct:
struct request {
uint8_t msg_type;// == 1
uint64_t key; // generated randomly to identify each request
}
In new implementation, I want to use boost::asio so in server I have a following piece of code:
boost::asio::io_service io_service;
boost::asio::ip::udp::endpoint client_endpoint;
boost::asio::ip::udp::socket socket(io_service,
boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(),
m_serverPort));
boost::asio::streambuf sb;
boost::asio::streambuf::mutable_buffers_type mutableBuf =
sb.prepare(sizeof(request));
size_t received_bytes = socket.receive_from(mutableBuf, client_endpoint);
sb.commit(received_bytes);
request r;
std::istream is(&sb);
is >> msg_type;
is >> key;
key = __bswap64(key); // I'm using network byteorder for numbers sent with this protocol
// and there's no ntohll function on Snow Leopard (at least I can't
// find one)
sb.consume(received_bytes);
And here’s my problem: the “key” value which I try to receive this way is wrong – I mean I get something that I did not send.
Here are my suspicions:
- __bswap64 does not convert network to host (little-endian) byteorder
- I misunderstood how to use boost::asio::streambuf with streams
- There’s some incompatibility between old C interface and boost (but I don’t think so
cause I’ve found out that boost functions are just wrappers for it)
EDIT:
hmm they say “don’t praise a ford till you get over”. Now I have a very similar issue in another place of my code. I have a following struct which is sent as a reply for request metioned above:
struct __attribute__ ((packed)) CITE_MSG_T
{
uint8_t msg_id;
uint64_t key; // must be the same as in request
uint16_t index; // part number
uint16_t parts; // number of all parts
CITE_PART_T text; // message being sent
};
//where CITE_PART_T is:
struct __attribute__ ((packed)) CITE_PART_T
{
uint16_t data_length;
char* data;
};
and following piece of code: http://pastebin.com/eTzq6AWQ.
Unfortunately there’s another bug in it and again I read something I haven’t sent – replyMsg.parts and replyMsg.index is always 0 although old implementation says they’re for example 3 and 10. What’s wrong this time? As you can see I take care of padding and I use read instead of operator>>. If you wonder why I read that struct field by field here’s an answer: A server sends two different structures, both beginning with msg_id, one if it succeceeds and another if it fails. Right now, I simply have no idea how to do it other way.
You’re using formatted input, as though the data being sent were textual — you need unformatted input. Read about the
std::istream::readmember function, as it’s what you should be using rather thanoperator>>.Note that this would have been immediately obvious if you had been checking the stream state after each extraction, as one always should in non-throw-away code.