1

I'm implementing a tcp server with boost asio library. In the server, I use asio::async_read_some to get data, and use asio::write to write data. The server code is something like that.

std::array<char, kBufferSize> buffer_;
std::string ProcessMessage(const std::string& s) {
   if (s == "msg1") return "resp1";
   if (s == "msg2") return "resp2";
   return "";
}
void HandleRead(const boost::system::error_code& ec, size_t size) {
  std::string message(buffer_.data(), size);
  std::string resp = ProcessMessage(message);
  if (!resp.empty()) {
    asio::write(socket, boost::asio::buffer(message), WriteCallback);
  }
  socket.async_read_some(boost::asio::buffer(buffer_));
}

Then I write a client to test the server, the code is something like

void MessageCallback(const boost::system::error_code& ec, size_t size) {
   std::cout << string(buffer_.data(), size) << std::endl;
}
//Init socket
asio::write(socket, boost::asio::buffer("msg1"));
socket.read_some(boost::asio::buffer(buffer_), MessageCallback);
// Or async_read
//socket.async_read_some(boost::asio::buffer(buffer_), MessageCallback);
asio::write(socket, boost::asio::buffer("msg1"));
socket.read_some(boost::asio::buffer(buffer_), MessageCallback);
// Or async_read
//socket.async_read_some(boost::asio::buffer(buffer_), MessageCallback);

If I run the client, the code will be waiting at second read_some, and output is:resp1.

If I remove the first read_some, the ouput is resp1resp2, that means the server done the right thing.

It seems the first read_some EAT the second response but don't give the response to MessageCallback function.

I've read the quesion at What is a message boundary?, I think if this problem is a "Message Boundary" problem, the second read_some should print something as the first read_some only get part of stream from the tcp socket.

How can I solve this problem?

UPDATE: I've try to change the size of client buffer to 4, that output will be:

resp
resp

It seems the read_some function will do a little more than read from the socket, I'll read the boost code to find out is that true.

Community
  • 1
  • 1
user2538425
  • 55
  • 2
  • 8
  • 1
    Could it be a [TCP message boundary issue](http://stackoverflow.com/a/9563694/478288)? – chrisaycock Jul 17 '13 at 04:23
  • @chrisaycock I've read the question you mentioned and update the question, I think if this is a message boundary issue, either the first read_some will get the whole "resp1resp2" or the second read_some should get something from the socket, am I right? – user2538425 Jul 17 '13 at 04:44
  • 1
    What is `asio::read_some`? I don't see such a free-function in Asio documentation. Could you correct your question so that it would reflect more precisely what you're doing? – Igor R. Jul 17 '13 at 09:33
  • [`async_read_some()`](http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/basic_stream_socket/async_read_some.html) is a member function and not a [free function](http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html). The code in this question does not make sense as `asio::async_read_some()` won't compile. – Sam Miller Jul 17 '13 at 16:21
  • @sam-miller, sorry, I mean use socket.async_read_some function, and make a mistake while I asking the question, I've updated the question. – user2538425 Jul 18 '13 at 01:03
  • @IgorR. I've update the code in the question. – user2538425 Jul 18 '13 at 01:03
  • I can't see the whole picture, but there're 2 common error-prone points: ensure that you never have 2 simultaneous `async_read`s or `async_write`s in progress; ensure that the buffers outlive the async.operations (`buffer` free-function doesn't copy the underlying buffer). – Igor R. Jul 18 '13 at 12:18
  • @IgorR. I've try to replace the async_read_some to read_some to make the read operation serial, that problem still exist. – user2538425 Jul 22 '13 at 02:29

1 Answers1

2

The async_read_some() member function is very likely not doing what you intend, pay special attention to the Remarks section of the documentation

The read operation may not read all of the requested number of bytes. Consider using the async_read function if you need to ensure that the requested amount of data is read before the asynchronous operation completes.

Note that async_read() free function does offer the guarantee that you are looking for

This operation is implemented in terms of zero or more calls to the stream's async_read_some function, and is known as a composed operation. The program must ensure that the stream performs no other read operations (such as async_read, the stream's async_read_some function, or any other composed operations that perform reads) until this operation completes.

Sam Miller
  • 23,808
  • 4
  • 67
  • 87