Stopping async_connect

Stopping async_connect

本文关键字:connect async Stopping      更新时间:2023-10-16

我目前使用Windows 7 64位,MSVC2010和Boost.Asio 1.57。我想连接到超时的 TCP 服务器。如果超时到期,我应该尽快关闭连接,因为 IP 地址(由用户选择)可能是错误的。

我知道我应该使用异步请求,因为同步请求不包含超时选项。所以我使用带有外部超时的async_connect。这是我在很多地方找到的解决方案,包括stackoverflow。

问题是下面的代码没有像我希望的那样运行。 async_connect 没有被 socket.close() "取消"。使用我的电脑,关闭套接字大约需要 15 秒才能完成,这使我的程序在一段时间内没有响应......我希望有一个体面的超时(大约 3 秒)并在这段时间之后关闭套接字,以便用户可以尝试使用另一个 IP 地址(从 HMI)连接

#include <iostream>
#include <boostasio.hpp>
#include <boostshared_ptr.hpp>
#include <boostbind.hpp>
using boost::asio::ip::tcp;
class tcp_client
{
public:
    tcp_client(boost::asio::io_service& io_service, tcp::endpoint& endpoint, long long timeout = 3000000) 
        :m_io_service (io_service),
        m_endpoint(endpoint),
        m_timer(io_service),
        m_timeout(timeout)
    {
        connect();
    }
    void stop()
    {
        m_socket->close();
    }
private:
    void connect()
    {
        m_socket.reset(new tcp::socket(m_io_service));
        std::cout << "TCP Connection in progress" << std::endl;
        m_socket->async_connect(m_endpoint,
            boost::bind(&tcp_client::handle_connect, this,
            m_socket,
            boost::asio::placeholders::error)
            );
        m_timer.expires_from_now(boost::posix_time::microseconds(m_timeout));
        m_timer.async_wait(boost::bind(&tcp_client::HandleWait, this, boost::asio::placeholders::error));
    }
    void handle_connect(boost::shared_ptr<tcp::socket> socket, const boost::system::error_code& error)
    {
        if (!error)
        {
            std::cout << "TCP Connection : connected !" << std::endl;
            m_timer.expires_at(boost::posix_time::pos_infin); // Stop the timer !
            // Read normally
        }
        else
        {
            std::cout << "TCP Connection failed" << std::endl;
        }
    }

public:
    void HandleWait(const boost::system::error_code& error)
    {
        if (!error)
        {
            std::cout << "Connection not established..." << std::endl;
            std::cout << "Trying to close socket..." << std::endl;
            stop();
            return;
        }
    }
    boost::asio::io_service&        m_io_service;
    boost::shared_ptr<tcp::socket>  m_socket;
    tcp::endpoint                   m_endpoint;
    boost::asio::deadline_timer     m_timer;
    long long                       m_timeout;
};
int main()
{
    boost::asio::io_service io_service;
    tcp::endpoint endpoint(boost::asio::ip::address_v4::from_string("192.168.10.74"), 7171); // invalid address
    tcp_client tcpc(io_service, endpoint);
    io_service.run();
    system("pause");
}

我找到的唯一解决方案是在许多线程中运行 io_service:run(),并为每个连接创建一个新套接字。但是这个解决方案对我来说似乎无效,因为我必须指定多个线程,并且我不知道用户将在我的HMI中输入多少个错误的地址。是的,有些用户不如其他用户聪明...

我的代码有什么问题?如何以干净快速的方式中断TCP连接?

此致敬意普基尔

代码没有任何基本错误,它在我的 Linux 盒子上完全符合您的要求:

TCP Connection in progress
Connection not established...
Trying to close socket...
TCP Connection failed
real    0m3.003s
user    0m0.002s
sys 0m0.000s

笔记:

  1. 您可能会成功向 stop() 函数添加cancel()调用:

    void stop()
    {
        m_socket->cancel();
        m_socket->close();
    }
    
  2. 不过,您应该检查超时的堕胎:

    void HandleWait(const boost::system::error_code& error)
    {
        if (error && error != boost::asio::error::operation_aborted)
        {
            std::cout << "Connection not established..." << std::endl;
            std::cout << "Trying to close socket..."     << std::endl;
            stop();
            return;
        }
    }
    

    否则,连接成功后计时器的隐式取消仍将关闭套接字:)

  3. 如果要并行运行(多次)连接尝试,则不需要更多线程甚至多个io_service。这就是 Boost Asio 的本质:您可以在单个线程上执行异步 IO 操作。

    • 这个答案给出了一个非常孤立的画面(即使连接是在那里使用 ZMQ 完成的):在 N 秒内两次提升 asio deadline_timer async_wait(N 秒)导致操作取消

    • 另一个例子,这次是关于在单个io_service上独立超时多个会话:boost::asio::d eadline_timer::async_wait不触发回调