How to restore a network using boost :: asio

I am writing a server that receives data from a device and processes it. Everything works fine if there is no interruption in the network (i.e. if I disconnect the Ethernet cable and then reconnect it). I use read_until () because the protocol that the device uses completes the packet with a specific sequence of bytes. When the data stream is interrupted, read_until () blocks, as expected. However, when the thread starts again, it remains blocked. If I watch the data stream with Wireshark, the device will continue to transmit, and each packet will be ACK'ed by the network stack. But if I look at bytes_readable, then it’s always 0. How can I detect an interrupt and how to reconnect to the data stream? Below is a snippet of code and in advance for any help you can offer. [Easy on me, this is my first question .... and yes, I tried to find the answer.]

using boost::asio::ip::tcp; boost::asio::io_service IOservice; tcp::acceptor acceptor(IOservice, tcp::endpoint(tcp::v4(), listenPort)); tcp::socket socket(IOservice); acceptor.accept(socket); for (;;) { len = boost::asio::read_until(socket, sbuf, end); // Process sbuf // etc. } 
+5
source share
2 answers

Remember that the client initiates the connection, so you only need to restore the socket and accept it again. I will keep the format of your snippet, but I hope that your real code will be encapsulated correctly.

 using SocketType = boost::asio::ip::tcp::socket; std::unique_ptr<SocketType> CreateSocketAndAccept( boost::asio::io_service& io_service, boost::asio::ip::tcp::acceptor& acceptor) { auto socket = std::make_unique<boost::asio::ip::tcp::socket>(io_service); boost::system::error_code ec; acceptor.accept(*socket.get(), ec); if (ec) { //TODO: Add handler. } return socket; } ... auto socket = CreateSocketAndAccept(IOservice, acceptor); for (;;) { boost::system::error_code ec; auto len = boost::asio::read_until(*socket.get(), sbuf, end, ec); if (ec) // you could be more picky here of course, // eg check against connection_reset, connection_aborted socket = CreateSocketAndAccept(IOservice, acceptor); ... } 

Footnote: Unless, of course, the socket must remain in scope.

Edit: based on the comments below.

The auditory socket itself does not know if the client is silent or disconnected. All operations, especially synchronous ones, must impose a restriction on completion. Consider setting SO_RCVTIMEO or SO_KEEPALIVE (for each socket or the whole system for more information. How to use the SO_KEEPALIVE parameter correctly to find that the client is not working from the other end? ).

Another option is to switch to async and implement a full-fledged “common” socket server (the example of the BOOST page is a great start).

In any case, you may run into data consistency problems and be forced to deal with it, for example. when the client detects an interrupted connection, it will resend the data. (or something more complicated using higher level protocols)

+2
source

If you want to stay synchronous, then, as I saw, the things being processed are to destroy the socket when you detect an interrupt. A blocking call should throw an exception that you can catch, and then start accepting connections again.

 for (;;) { try { len = boost::asio::read_until(socket, sbuf, end); // Process sbuf // etc. } catch (const boost::system::system_error& e) { // clean up. Start accepting new connections. } } 

As Tom mentions in his answer, there is no difference between inactivity and inhuman outage, so you need an external mechanism to detect this.

If you expect continuous data transfer, maybe one timeout per server-side connection is enough. Simple ping can also work. After accepting the connection, ping your client every X seconds and declare the connection dead if it does not respond.

+1
source

Source: https://habr.com/ru/post/1270899/


All Articles