0
votes

The implementation:

The client uses async_write to sending messages to the server. In the write handler, it starts next async_write operation.

The server uses async_read to receive messages from the client. In the read handler, it starts next async_read operation.

I want to stop the async operation immediately when the remote side is closed.

When I close the client, the async_read calls the handler immediately with an boost::asio::error::eof error code. But when the server is closed, the client continues writing. How can I make it call the handler with an error code?

2
You can't, because you don't know immediately. The only way you can detect it is by doing a write, and you will almost certainly only detect it on a subsequent write.user207421
If the socket is closed then async_read will instantly return with an error. As long as you are polling async_read and check error then you shouldn't need to worry about async_write failing.Nina
@user207421 yes, I actually did the write. The return value in the write handler indicates that I successfully transferred the whole message and didn't get an error. I think the message is written to a buffer or something. What does 'detect it by doing a write' mean?shb
@Nina The error in async_read is what I want, but I also want to let the writing side know the closing event and do something(such as clear the message queue)shb
Asnyc_write will also return to the callback with an error if the socket is closed. But typically you just handle the error in the async_read callback. From there you can clear your write queue because your async_write will also have returned.Nina

2 Answers

0
votes

In simple terms your design should look like this:

Call async_read

When you need to write

Call async_write

Do not call async_write again until the previous async_write call has returned. If you need to call multiple async_write operations, then que your buffers.

Call async_write
callback pull next buffer from que
Call async_write
callback pull next buffer from que
Call async_write
callback pull next buffer from que

By doing this, you're ensuring this only one async_write operating is in effect at all times per socket. Which is how it should be. Do NOT do this.

Call async_write
Call async_write
Call async_write
callback
callback
callback

This is where you run into issues by trying to stop async_write after a read operation has occurred with an error. When async_read returns with an error you no longer have to take extra steps in your async_write operation to cancel concurrent calls.

Call async_read
Call async_write
async_read callback returns with error (do not call async_read again)
async_write returns with error (do not call async_write again)

So when calling async_write check a flag (iswriting) if the flag is true, then push your buffer into your que. When the callback returns, check your que, pull the next buffer and call async_write again. If iswriting is false, then just call async_write instead of pushing it to the que. If your callback returns and your que is finally empty then set iswriting to false again.

This is all pretty straight forward...

0
votes

You read/write, in other words you have a protocol, so add a new flag (message, bit ...) saying that you will close the socket, and close the socket only when that message has been received. Of course your protocol must handle errors.