EOF при выполнении async_read_some () на сокете TCP ... Но соединение все еще установлено - PullRequest
0 голосов
/ 18 января 2019

Я расследую странную проблему с фрагментом кода, который обрабатывает соединение через сокет TCP: каждые 10 минут наш клиент получает ошибку EOF при чтении данных с использованием boost async_read_some (). Обычно это происходит, когда соединение клиента <-> с сервером потеряно, и поэтому наш клиент корректно закрывает соединение, а затем снова открывает его.

Однако, при более глубоком рассмотрении причины ошибки EOF я обнаружил, что:

  1. Сервер не получает ту же ошибку EOF, что и клиент (они оба используют один и тот же код для обработки связи), в то время как он успешно обнаруживает отключение клиента, когда я уничтожаю процесс клиента.
  2. На самом деле соединение установлено: отключив код переподключения и игнорируя ошибку, клиент и сервер продолжают обмен данными без проблем ...
  3. Как и в пункте 2, ошибка EOF больше не возникает, поэтому кажется, что она возникает только один раз, через 10 минут после установления соединения.

Кто-нибудь имеет представление о том, почему я получил этот EOF? Я использую Boost v1.56.0 в Gentoo Linux.

Заранее спасибо. SiS.

РЕДАКТИРОВАТЬ: Это упрощенная версия кода, которая вызывает у меня проблему (извините, но я не могу опубликовать фактическую):

#include <boost/asio.hpp>
#include <boost/function.hpp>
#include <boost/signals2.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <cstddef>

static const unsigned int g_reconnect_time = 15; // Seconds

class conn_t
{
public:

    conn_t( std::string ip, int port, boost::asio::io_service& io_service ) :
        m_tcp_host(ip),
        m_tcp_port(port),
        m_io_service( io_service ),
        m_socket( io_service ),
        m_reconnect_interval( g_reconnect_time ),
        m_reconnect_timer( io_service, m_reconnect_interval )   
    {
    }


    ~conn_t()
    {
        disconnect();
    }   


    bool connect()
    {
        using boost::asio::ip::tcp;
        tcp::resolver resolver( m_io_service );
        tcp::resolver::query query( tcp_host, m_tcp_port);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve( query );
        tcp::resolver::iterator end;
        boost::system::error_code error = boost::asio::error::host_not_found;

        while ( error && ( endpoint_iterator != end ) )
        {
            m_socket.close();
            m_socket.connect( *endpoint_iterator++, error );
        }

        if ( error ) 
        {
            // Bail out and schedule for retry:
            queue_reconnect();
            return false;
        }

        if ( !m_socket.is_open() )
            return false;

        read_data();
        return true;
    }


    void disconnect()
    {
        m_socket.close();
    }


    void read_data()
    {
        m_socket.async_read_data_some( boost::asio::buffer( m_buff ),
            [this]( const boost::system::error_code& error, std::size_t len )
            {
                if ( handle_error( error ) )
                {
                     std::cerr << "Error read_dataing data: " << std::endl;
                    reconnect();
                } 
                else 
                {
                    std::cerr << "got " << len << " bytes of data" );
                    // process data here...
                    read_data();
                }
            } );
    }


    void reconnect()
    {
        queue_reconnect();
    }


private:

    bool handle_error ( const boost::system::error_code& error )
    {
        if ( error && error != boost::asio::error::operation_aborted ) 
        {
            std::cerr << "Socket i/o error: " << error.message() << std::endl;
            boost::system::error_code ignored_ec;
            m_socket.shutdown( boost::asio::ip::tcp::socket::shutdown_both, ignored_ec );
            m_socket.close();

            return true;
        }
        return false;
    }


    void queue_reconnect()
    {
        auto new_deadline = m_reconnect_timer.expires_at() + m_reconnect_interval;

        if ( new_deadline > boost::asio::deadline_timer::traits_type::now() )
            m_reconnect_timer.expires_at( new_deadline );
        else
            m_reconnect_timer.expires_from_now( m_reconnect_interval );

        m_reconnect_timer.async_wait( boost::bind( &conn_t::start, this ) );

    }

private:

    std::string tcp_host;
    int m_tcp_port;
    boost::asio::io_service& m_io_service;
    boost::asio::ip::tcp::socket  m_socket;
    boost::posix_time::seconds m_reconnect_interval;
    boost::asio::deadline_timer m_reconnect_timer;
    char m_buff[1024];
};
...