0

Observation

I built a demo application according to this server example using ASIO after I used C++11 std to replace everything originally in boost. The server can show that class member tcp_session::start() is called only after the client connects which is good indication that the server accepts the connection from the client.

However, I saw nothing received by handle_read while the clients sends a lot of data. I got some std::cout in handle_read and stop. I put the timeout to be 6 seconds now and found this: The start is called right after the client connects, and then nothing indicating that the handle_read is called, but after 6 seconds, stop() is called, and then handle_read is called because of the timeout and socket_.isOpen() is false.

Then I found that if I change async_read to async_read_until that was commented originally by me, then the handle_read will be called andthe socket_.isopen is true so I can really see the packets.

Question:

The delimiter was there but I don't want one. How do I async read a whole TCP string without a delimiter? Why async_read doesn't work? Should it work like this? Is there anything wrong in my code?

I am using VS2015 and test on localhost.

Answer

TCP doesn't have boundary so I decided to put special character to indicate the end of each packet.

Here are some relevant code:

class tcp_session : public subscriber, public  std::enable_shared_from_this<tcp_session> {
public:
void start() {
    std::cout<<"started"<<std::endl;
    channel_.join(shared_from_this());
    start_read();
    input_deadline_.async_wait(
        std::bind(&tcp_session::check_deadline, shared_from_this(), &input_deadline_)
        );
    await_output();

    output_deadline_.async_wait(
        std::bind(&tcp_session::check_deadline, shared_from_this(), &output_deadline_)
    );
}
private:    
bool stopped() const {
    return !socket_.is_open();// weird that it is still not open
}
void start_read() {

    // Set a deadline for the read operation.
    input_deadline_.expires_from_now(timeout_); //was std::chrono::seconds(30) in example
    char a = 0x7F;
    // Start an asynchronous operation to read a 0x7F-delimited message or read all
    //asio::async_read_until(socket_, input_buffer_, a, std::bind(&TCP_Session::handle_read, shared_from_this(), std::placeholders::_1));

    asio::async_read(socket_, input_buffer_, 
            std::bind(&TCP_Session::handle_read, shared_from_this(), std::placeholders::_1));
}
void handle_read(const asio::error_code& ec) {
    if (stopped()) // it thinks it stopped and returned without processing
        return;
Splash
  • 1,288
  • 2
  • 18
  • 36
  • Can you please elaborate as to what "read a whole TCP string" means? Do you wish to read at-least `n` bytes, exactly `n` bytes, some available bytes, all available bytes? This [answer](http://stackoverflow.com/a/28931673/1053968) explains why `async_read(streambuf)` is not immediately completing upon reading some data: the `async_read()` operation is trying to read `std::numeric_limits< std::size_t >::max` bytes. – Tanner Sansbury Dec 04 '15 at 18:28
  • @TannerSansbury: example is, client sends Modbus TCP packet which is [six bytes][address command ..... ]. I want to read all of them. Then, I will send a packet, and the client will read all of them. Then client sends another packet, and server reads all of them. – Splash Dec 04 '15 at 20:03
  • 1
    TCP is a stream of data that has already been reassembled from lower-level packets. As a result, there is no way to specify "read all of them". To provide message boundaries, Modbus TCP has a 7-byte fixed-length header in big-endian format that includes a length field and is followed by a variable-length body. The official Asio [chat example](http://www.boost.org/doc/libs/1_59_0/doc/html/boost_asio/examples/cpp11_examples.html#boost_asio.examples.cpp11_examples.chat) demonstrates one way to handle fix-length header and variable-length body protocols. – Tanner Sansbury Dec 04 '15 at 21:31
  • @TannerSansbury: I finally had to accept this fact, and either use a length or a special character to tell the end of the packet. My packet is actually JSON, so I will use a carriage return at the end of the file – Splash Dec 04 '15 at 22:11

0 Answers0