Search code examples
c++socketstcpbufferboost-asio

How to use boost::asio::async_write(socket_, boost::asio::buffer(data, size) to write an int value?


I am trying to return an integer to the netcat(tcp) terminal, every time the message sent is Coop25, but this has generated a strange response on the terminal. The response is an instead of the integer and looks like this:

NETCAT TERMINAL:

Coop25
����

I have tried this function:

void tcp::tcp_session::do_write()
{ 
    std::array<int, 1> test{1};
    auto self(shared_from_this());
    boost::asio::async_write(socket_, boost::asio::mutable_buffer(test.data(), test.size),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
}

But when I try using some string this works:

std::string ret_mess_check{"blabla"}
const char* mess_to_reply = ret_mess_check.c_str();
do_write(mess_to_reply, strlen(mess_to_reply)); 

void tcp::tcp_session::do_write(const char* reply, std::size_t length)
{ 
    auto self(shared_from_this());
    boost::asio::async_write(socket_, boost::asio::buffer(reply, length),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
}

After @sehe's considerations, I am doing something like this:

in a .hpp file, declaring the mv num_status_{-1};

boost::array<int, max_length> num_status_{-1};

in a .cpp file, defining the do_write() function, like this:

void dac_sim::tcp::tcp_session::do_write()
{ 
    auto self(shared_from_this());
    boost::asio::async_write(socket_, boost::asio::buffer(num_status_),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
}

If I replace the member variable from an int to a string, everything works fine. With an int, the "����" still appears instead of -1 in this case.


Solution

  • You send /buffers/. Your code doesn't compile as given. For starters test.size is a pointer-to-member-function. Even if you meant test.size() then it would only send 1 byte, because test.size() returns 1. Also, you're using mutable_buffer when you don't need mutability. I'd write both incantations much simpler and much less error-prone:

    void tcp::tcp_session::do_write(std::string_view reply) {
        async_write(socket_, asio::buffer(reply),
                    [this, self = shared_from_this()](error_code ec, size_t /*length*/) {
                        if (!ec)
                            do_read();
                    });
    }
    
    void tcp::tcp_session::do_write() {
        async_write(socket_, asio::buffer(test),
                    [this, self = shared_from_this()](error_code ec, size_t /*length*/) {
                        if (!ec)
                            do_read();
                    });
    }
    

    You can even combine the two generically:

    void tcp::tcp_session::do_write(auto const& reply) {
        async_write(socket_, asio::buffer(reply),
                    [this, self = shared_from_this()](error_code ec, size_t /*length*/) {
                        if (!ec)
                            do_read();
                    });
    }
    

    And it would work for strings, array<int, 1>, std::vector<myComplicatedPodType> and even double[32] etc. etc.

    You can even combine them in a buffer-sequence:

    async_write(socket_, std::array{asio::buffer(test), asio::buffer(ret_mess_check)},
                [this, self = shared_from_this()](error_code ec, size_t /*length*/) {
                    if (!ec)
                        do_read();
                });
    

    Side Note

    Another thing to note about the question code that you MUST NOT use a local variable (like your test array) in an asynchronous operation, because it causes Undefined Behaviour because the buffer refers to an object whose lifetime ends before the asynchronous operation completes.