[ASIO] Correct way to reconnect a failed TCP connection
Hello, I am having a little trouble getting my boost::ASIO TCP client to actually re-attempt a connected if the first attempt failed. With my server offline, the call to async_connect correctly times out. When I try the async_connect call a second time, it doesn't time out. I am running my io_service listener in a boost thread, and am not changing this between async_connect calls. However, my debugger (MSVC2005, boost 1.35) does show a thread exit at this time. I don't think its the relevant thread (at the second call to connect there is an extra thread running (the io_service I guess). Here's my two relevant files. Thanks very much for any pointers Simon // Network.cpp //-------------------- // CNetwork::Connect // ........ m_client = boost::shared_ptr<CASIOClient>( new CASIOClient( m_log, m_initXML, m_IO, this ) ); try { tcp::resolver resolver(*(m_IO.get())); tcp::resolver::query query( m_serverHost.c_str(), m_serverPort.c_str() ); tcp::resolver::iterator iterator = resolver.resolve(query); m_client->Connect(iterator); m_log->NET( "Looking for Server at %s:%s\n", m_serverHost.c_str(), m_serverPort.c_str() ); } catch (boost::system::error_code& e) { m_log->NET("%s\n", e.message().c_str() ); m_log->NET("Server not found?\n"); return -1; } catch (std::exception& e) { m_log->NET("Exception %s\n", e.what() ); return false; } // start the io service to listen for async ops if ( !m_listener ) m_listener = boost::shared_ptrboost::thread( new boost::thread(boost::bind(&boost::asio::io_service::run, m_IO.get()) ) ); //------------------------------------- // CASIOClient.cpp CASIOClient::CASIOClient( boost::shared_ptr<ILogInterface> log, boost::shared_ptr<IXMLInterface> xml, boost::shared_ptrboost::asio::io_service io, CNetwork* network ): m_IO(io), m_socket(*(io.get())), m_network(network) { m_log = log; m_initXML = xml; } void CASIOClient::Connect( tcp::resolver::iterator endpoint_iterator ) { tcp::endpoint endpoint = *endpoint_iterator; m_socket.async_connect( endpoint, boost::bind( &CASIOClient::HandleConnect, this, boost::asio::placeholders::error, ++endpoint_iterator)); m_connectionState = NETWORK_DISCONNECTED; } void CASIOClient::Close() { m_log->NET("Starting Close...\n"); m_IO->post(boost::bind(&CASIOClient::DoClose, this)); } ////////////////////////////////////////// void CASIOClient::HandleConnect( const boost::system::error_code& error, tcp::resolver::iterator endpoint_iterator) { if (!error) { m_log->NET("Connected: %s\n", error.message().c_str()); m_connectionState = NETWORK_CONNECTED; boost::asio::async_read_until( m_socket, m_rx, '@', // termination char boost::bind( &CASIOClient::HandleReadUntil, this, boost::asio::placeholders::error)); } else if (endpoint_iterator != tcp::resolver::iterator()) { m_log->NET("Connection unsuccessful: %s\n", error.message().c_str()); m_log->NET("Retrying\n"); tcp::endpoint endpoint = *endpoint_iterator; m_socket.async_connect( endpoint, boost::bind( &CASIOClient::HandleConnect, this, boost::asio::placeholders::error, ++endpoint_iterator)); } else { m_log->NET("Connect Error: %s\n", error.message().c_str()); DoClose(); } } void CASIOClient::HandleReadUntil(const boost::system::error_code& error) { if (!error) { std::istreambuf_iterator<char> iter(&m_rx); std::istreambuf_iterator<char> end; std::string read(iter, end); std::string clipMsg; while (read.length()) { int n = read.find("@"); clipMsg = read.substr( 0, n ); m_log->NET( "Message received: %s\n", clipMsg.c_str() ); m_network->QueueReceivedMessage( clipMsg ); read = read.substr( n+1, read.length()-n-1 ); } // start listening again boost::asio::async_read_until( m_socket, m_rx, '@', boost::bind( &CASIOClient::HandleReadUntil, this, boost::asio::placeholders::error)); } else { m_log->NET( "ReadUntil Error: %s\n", error.message().c_str() ); DoClose(); } } void CASIOClient::DoClose() { m_log->NET( "Closing ASIO\n" ); m_socket.close(); m_connectionState = NETWORK_FAILED; }
I am having a little trouble getting my boost::ASIO TCP client to actually re-attempt a connected if the first attempt failed. With my server offline, the call to async_connect correctly times out. When I try the async_connect call a second time, it doesn't time out.
It's unclear from your code where/how you try to re-connect. IIUC, your HandleConnect() function doesn't reconnect, but just iterates over the endpoints that you were given by the address resolver... So if you've got 1 endpoint, then the 1st time you get into HandleConnect with some error - you call DoClose(), and if the io_service has no more work, it just ends (with the whole thread).
participants (2)
-
Igor R
-
Simon Pickles