asio::ip::tcp::socket auto reconnect by io_service

Viewed 40

Under Ubuntu 2404LTS with boost version 1.65.1.

I use io_service to initiate asio::ip::tcp::socket async_connect and get socket1, then I read several messages from it.

After receving some specific message from socket1, I call io_service::stop() with remaining/unhandler handler in the io_service and explicitly invoke socket1.close(), and check ec is 0 so the close is successful.

This is the magic part, I call io_service::reset() and after I try to create another socket2 and run io_service::run() again, this also initiate connect for socket1, so there are now 2 live sockets.

What's happening here? I think it may be caused by the remaining handlers in the io_service object, but how come it will initiate connect for the socket1?

1 Answers

We can't tell without seeing the code, but my suspicion is to undefined behaviour.

Here's a literal implementation of your description:

Live On Coliru

#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
using boost::system::error_code;

int main()
{
    std::cout << std::boolalpha;

    asio::io_service ios;

    tcp::socket socket1(ios);

    {
        asio::streambuf buf;
        socket1.async_connect({{}, 8787}, [&](error_code ec) {
                std::cout << "socket1 now connected (" << ec.message() << ") to "
                << socket1.remote_endpoint() << std::endl;

                async_read_until(
                    socket1, buf, "some_specific_message", [&](error_code ec, size_t n) {
                        std::cout << "Received some specific message (" << ec.message()
                                  << ") at " << n << " bytes" << std::endl;

                        ios.stop();
                        std::cout << "ios stopped: " << ios.stopped() << std::endl;
                        socket1.close();
                        std::cout << "socket1 closed: " << !socket1.is_open() << std::endl;
                    });
                });

        ios.run();
    }

    std::cout << "about to reset" << std::endl;
    ios.reset(); // consider using restart()

    tcp::socket socket2(ios);
    socket2.async_connect({{}, 9898}, [&](error_code ec) {
        std::cout << "socket2 now connected (" << ec.message() << ") to "
                  << socket2.remote_endpoint() << std::endl;
    });

    ios.run();

    std::cout << "socket1.is_open(): " << socket1.is_open() << std::endl;
    std::cout << "socket2.is_open(): " << socket2.is_open() << std::endl;
}

When we open to services:

(cat main.cpp ; sleep 3; echo "some_specific_message") | netcat -l -p 8787 &
echo "hello socket2" | netcat -l -p 9898 &

We get the output:

socket1 now connected (Success) to 127.0.0.1:8787
Received some specific message (Success) at 570 bytes
ios stopped: true
socket1 closed: true
about to reset
socket2 now connected (Success) to 127.0.0.1:9898
socket1.is_open(): false
socket2.is_open(): true

As you can see, only socket2 is open. Here's a live demo:

enter image description here

Feel free to edit the example to show how it is failing. When you do, you might notice the problem in your code.

Related