首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在断开连接后干净地重新连接boost::socket?

如何在断开连接后干净地重新连接boost::socket?
EN

Stack Overflow用户
提问于 2010-06-17 22:55:26
回答 5查看 26.3K关注 0票数 29

我的客户端应用程序使用boost::asio::ip::tcp::socket连接到远程服务器。如果应用程序失去与此服务器的连接(例如,由于服务器崩溃或关闭),我希望它尝试定期重新连接,直到成功。

我需要在客户端做些什么才能干净利落地处理断开连接、整理并重复尝试重新连接?

目前,我的代码中有趣的部分看起来像这样。

I connect就像这样:

代码语言:javascript
复制
bool MyClient::myconnect()
{
    bool isConnected = false;

    // Attempt connection
    socket.connect(server_endpoint, errorcode);

    if (errorcode)
    {
        cerr << "Connection failed: " << errorcode.message() << endl;
        mydisconnect();
    }
    else
    {
        isConnected = true;

        // Connected so setup async read for an incoming message.
        startReadMessage();

        // And start the io_service_thread
        io_service_thread = new boost::thread(
            boost::bind(&MyClient::runIOService, this, boost::ref(io_service)));
    }
    return (isConnected)
}

其中runIOServer()方法只是:

代码语言:javascript
复制
void MyClient::runIOService(boost::asio::io_service& io_service)
{
    size_t executedCount = io_service.run();
    cout << "io_service: " << executedCount << " handlers executed." << endl;
    io_service.reset();
}

如果任何异步读取处理程序返回错误,则它们只需调用此disconnect方法:

代码语言:javascript
复制
void MyClient::mydisconnect(void)
{
    boost::system::error_code errorcode;

    if (socket.is_open())
    {
        // Boost documentation recommends calling shutdown first
        // for "graceful" closing of socket.
        socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, errorcode);
        if (errorcode)
        {
            cerr << "socket.shutdown error: " << errorcode.message() << endl;
        }

        socket.close(errorcode);
        if (errorcode)
        {
            cerr << "socket.close error: " << errorcode.message() << endl;
        }    

        // Notify the observer we have disconnected
        myObserver->disconnected();            
    }

..which尝试正常断开连接,然后通知观察者,观察者将以五秒的间隔开始调用connect(),直到重新连接为止。

还需要我做什么吗?

目前,这似乎确实有效。如果我杀死它所连接的服务器,我会在我的读处理程序中得到预期的"End of file"错误,并且mydisconnect()被调用时没有任何问题。

但是当它尝试重新连接并失败时,我看到它报告"socket.shutdown error: Invalid argument"。这仅仅是因为我试图关闭一个没有读/写挂起的套接字吗?或者是更多的东西?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-06-19 06:06:27

每次重新连接时都需要创建一个新的boost::asio::ip::tcp::socket。要做到这一点,最简单的方法可能是使用boost::shared_ptr在堆上分配套接字(如果套接字完全封装在类中,也可以使用scoped_ptr )。例如:

代码语言:javascript
复制
bool MyClient::myconnect()
{
    bool isConnected = false;

    // Attempt connection
    // socket is of type boost::shared_ptr<boost::asio::ip::tcp::socket>
    socket.reset(new boost::asio::ip::tcp::socket(...));
    socket->connect(server_endpoint, errorcode);
    // ...
}

然后,当调用mydisconnect时,您可以释放套接字:

代码语言:javascript
复制
void MyClient::mydisconnect(void)
{
    // ...
    // deallocate socket.  will close any open descriptors
    socket.reset();
}

您看到的错误可能是操作系统在您调用close之后清除了文件描述符的结果。当您调用close,然后尝试在同一套接字上执行connect时,您可能正在尝试连接无效的文件描述符。此时,您应该看到一条以"Connection failed:...“开头的错误消息。基于您的逻辑,但是您随后调用了mydisconnect,而后者随后可能试图在无效的文件描述符上调用shutdown。恶性循环!

票数 29
EN

Stack Overflow用户

发布于 2010-06-25 19:49:45

为了清楚起见,这里是我使用的最后一种方法(但这是基于bjlaub的回答,所以请对他表示赞赏):

我将socket成员声明为scoped_ptr

代码语言:javascript
复制
boost::scoped_ptr<boost::asio::ip::tcp::socket> socket;

然后我将我的connect方法修改为:

代码语言:javascript
复制
bool MyClient::myconnect()
{
    bool isConnected = false;

    // Create new socket (old one is destroyed automatically)
    socket.reset(new boost::asio::ip::tcp::socket(io_service));

    // Attempt connection
    socket->connect(server_endpoint, errorcode);

    if (errorcode)
    {
        cerr << "Connection failed: " << errorcode.message() << endl;
        socket->close();
    }
    else
    {
        isConnected = true;

        // Connected so setup async read for an incoming message.
        startReadMessage();

        // And start the io_service_thread
        io_service_thread = new boost::thread(
            boost::bind(&MyClient::runIOService, this, boost::ref(io_service)));
    }
    return (isConnected)
}

注意:这个问题最初是在2010年提出并回答的,但如果您现在使用C++11或更高版本,那么std::unique_ptr通常会是比boost::scoped_ptr更好的选择

票数 8
EN

Stack Overflow用户

发布于 2018-08-16 18:34:44

从C++11开始,你可以这样写:

代码语言:javascript
复制
decltype(socket)(std::move(socket));
// reconnect socket.

上面的代码创建了socket类型move的本地实例,从socket构造它。

在下一行之前,未命名的本地实例被析构,使套接字处于“从io_service新构造的”状态。

请参阅:https://www.boost.org/doc/libs/1_63_0/doc/html/boost_asio/reference.html#boost_asio.reference.basic_stream_socket.basic_stream_socket.overload5

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3062803

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档