I'm building a tcp client that must send requests and read responses, but also must be able to detect incoming data from the tcp server that is not a response to a request - the server can originate a tx/rx sequence.
What is the best way to keep an async read active all the time. I tried the following:
In my "handle_connect" method I start an async read and also an async write. The async read looks like this:
size_t bytes_transferred = BUFFER_SIZE; boost::asio::async_read(m_socket, boost::asio::buffer(rcvbuf, bytes_transferred), boost::bind(&CClientSock::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
The async write fills a buffer and then starts the write:
boost::asio::async_write(m_socket, boost::asio::buffer(sndbuf, request_length), boost::bind(&CClientSock::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
In the async write handler - it does nothing since the async read is already started.
This doesn't work. The data that should be read from the server's response to the client's write never triggers the async read handler. I'm not actually certain the write ever executes...
Can this be done since the reads and writes are not queued in the normal order? Would I have to start a read, then cancel it if I needed to start a write?
In absense of a clear SSCCE/sample, I'll highlight a few ideas:
strand
: Why do I need strand per connection when using boost::asio?
to keep reading, in Actor Based asynchrony, just post the read operation from within the completion handler for the previous read operation:
void handle_read(boost::system::error_code ec, size_t bytes_received) {
if (!ec)
{
/* do your usual handling on the incoming data */
boost::asio::async_read(m_socket,
boost::asio::buffer(rcvbuf, bytes_transferred),
boost::bind(&CClientSock::handle_read,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
Well, I have the answer to my initial question, but sehe brought up the possibility of using strands so I may not have a complete understanding.
My initial problem was the result of restructuring code and not realizing my earlier code worked only under the circumstances that I tested against. I now have this working using the following sequence:
This sequence seems to be repeatable indefinitely without error.
Regarding strands - the code is multi-threaded so there are multiple threads and each thread may be managing multiple socket connections. There are no socket calls across threads - that is, a socket is never acted on by code other than in the thread where the socket was created. However, there is only one io_service object for the project, which seems to be the recommended way to use the io_service object in a multi-thread application.
Am I correct that strands are not necessary here?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With