Tcp-klient nie zgłosi błąd podczas łączenia się z lokalnym hostem, jeśli serwer nie jest gotowy

0

Pytanie

Próbowałem hermetyzacji wszystkie funkcje sieciowe dla swojego programu w klasy "SimpleClient", który zapewnia ten interfejs wewnątrz pliku .hpp:

class SimpleClient{
    //private
        boost::shared_ptr<boost::asio::ip::tcp::socket> signal_socket; 
    protected: 
        boost::asio::io_context my_context;
        ClientState state; //0: Ready to be used, not connected,  -1: error, 1: Connected/active, 
    public: 
       SimpleClient();
       virtual bool connect(const char* ip_address);
       virtual void disconnect();
       virtual bool sendMessage(const char* msg, int length);
       virtual int getResponse( char* msg, int length, int timeout);
       virtual int getSignalData( char* msg, int length);
       virtual ClientState getState();
};

Podczas testowania metody połączenia zauważyłem, że nawet jeśli żaden serwer nie czekał na lokalnym hoście na porcie 8887, połączenie nie wydawał błędy. Jak mogę sprawdzić, czy gniazdko jest podłączone naprawdę?

Oto metody, które osiągnąłem, i mały przykład, który odtwarza moje zachowanie, za pomocą boost.test:

SimpleClient::SimpleClient() : my_context() {
    signal_socket.reset();
    state = ClientState::CL_UNCON;
}

bool SimpleClient::connect(const char* ip_address) {
    boost::system::error_code ec;
    if (signal_socket != NULL && signal_socket->is_open() )
        return true;
    try {
        boost::asio::ip::tcp::endpoint signal_endpoint(boost::asio::ip::make_address(ip_address), 8887);
        signal_socket.reset(new boost::asio::ip::tcp::socket(my_context));
        signal_socket->connect(signal_endpoint, ec);
        if(ec) {
            std::cout<<ec.message()<<" "<<ec.value()<<std::endl;
            return false;
        }
    } catch(const boost::system::system_error& ex) {
        std::cout<<ex.code()<<std::endl;
        return false;
    }
    std::cout<<signal_socket<<std::endl;
    state = ClientState::CL_READY;
    return true;
}

Oto program testowania:

#define BOOST_AUTO_TEST_MAIN 
#define BOOST_TEST_DYN_LINK

#include "SimpleClient.hpp"

#include <boost/test/unit_test.hpp>

#include <string.h>

#define TARGET_IP "127.0.0.1"
#define BAD_IP "128.0.0.1"


BOOST_AUTO_TEST_CASE(connection_test)  {
    bool ret;
    std::cout<<"Connect to WRONG address"<<std::endl;
    SimpleClient* ut = new SimpleClient();
    BOOST_CHECK_EQUAL(ut->getState(), ClientState::CL_UNCON);
    ret = ut->connect(BAD_IP);
    BOOST_CHECK(!ret);
    std::cout<<"Connect to RIGHT address"<<std::endl;
    ret = ut->connect(TARGET_IP);
    BOOST_CHECK(ret);
    ut->disconnect();
    try{
        delete ut;
    }
    catch(const std::exception& ex) {
        std::cout<<ex.what()<<std::endl;
    }
    catch(...) {
    }
} 
boost boost-asio c++ tcp
2021-11-22 09:30:07
1

Najlepsza odpowiedź

1

Oczywiście, problem polegał w moim sposobie podłączenia. Pierwsze połączenie połączenia wewnątrz mojego testu nie udało, ale nie zamknął gniazdo, więc drugie połączenie automatycznie zwrócił wartość true, bez wykonania jakiejkolwiek operacji.

TLDR: w przypadku awarii connect nie zamyka gniazdo, i każdy wywołanie funkcji is_open() zwraca "true", należy wywołać metodę ręcznego zamknięcia() do gniazda w przypadku błędu.

bool SimpleClient::connect(const char* ip_address) {
    boost::system::error_code ec;
    if (signal_socket != NULL && signal_socket->is_open() )
        return true;
    try {
        boost::asio::ip::tcp::endpoint signal_endpoint(boost::asio::ip::make_address(ip_address), 8887);
        signal_socket.reset(new boost::asio::ip::tcp::socket(my_context));
        signal_socket->connect(signal_endpoint, ec);
        if(ec) {
            std::cout<<ec.message()<<" "<<ec.value()<<std::endl;
            signal_socket->close();
            signal_socket.reset();
            return false;
        }
    } catch(const boost::system::system_error& ex) {
        std::cout<<ex.code()<<std::endl;
        signal_socket->close();
        signal_socket.reset();
        return false;
    }
    std::cout<<signal_socket<<std::endl;
    state = ClientState::CL_READY;
    return true;
}
2021-11-22 14:52:56

Alternatywnie, aby wyregulować przepływ sterowania tak, aby gniazdo nie był używany po błędu. To bardziej naturalne podejście. Często kontrola "is_open" - to nie to, co trzeba w każdym przypadku (na przykład, nie będzie w stanie określić, kiedy zdalny koniec zamknął połączenie). +1 za odpowiedź na własne pytanie, choć!
sehe

W innych językach

Ta strona jest w innych językach

Русский
..................................................................................................................
Italiano
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................