如果没有服务器准备好,tcp 客户端在连接到 localhost 时不会抛出错误

Posted

技术标签:

【中文标题】如果没有服务器准备好,tcp 客户端在连接到 localhost 时不会抛出错误【英文标题】:tcp client does not throw error while connecting to localhost if no server is ready 【发布时间】:2021-12-31 22:06:46 【问题描述】:

我尝试将我的程序的所有网络功能封装在“SimpleClient”类中,该类在 .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();
;

在测试连接方法时,我注意到即使没有服务器在 localhost 的 8887 端口上等待,连接也没有抛出错误。如何检查套接字是否真实连接?

这里是我实现的方法和一个使用 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;

这是测试程序:

#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(...) 
    
 

【问题讨论】:

无关:作为随机测试的一部分,请不要向陌生人的计算机发送垃圾邮件。 您是否尝试过在 strace 等系统调用监控工具下运行程序以查看连接是否真的失败? 非常感谢,我找到了问题 【参考方案1】:

很明显,问题出在我的 connect 方法中。我的测试中第一次调用 connect 失败,但它没有关闭套接字,所以第二次调用自动返回 true,没有执行任何操作。

TLDR:在失败的情况下,connect 不会关闭套接字,任何对 is_open() 的调用都会返回 'true',如果出错,请在套接字上手动调用 close() 方法.

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;

【讨论】:

另外调整控制流,以便在出错后不使用套接字。这是更自然的方法。通常检查“is_open”并不是你想要的(例如,它无法检测到远程端何时关闭连接)。 +1 回答您自己的问题!

以上是关于如果没有服务器准备好,tcp 客户端在连接到 localhost 时不会抛出错误的主要内容,如果未能解决你的问题,请参考以下文章

JS Websocket 卡在连接到 TCPListener 的状态 - VB.net

TCP协议介绍

为啥客户端没有连接到我的 tcp 服务器?

VS code remote x11 在连接到远程服务器时无法显示

如果已经连接了相同的 JID,XMPP 客户端可以连接到服务器吗?

iPhone 定位服务在连接到 XCode 后显示错误的位置