【问题标题】:How do i detect if a particular tcp stream connected through boost::asio_stream_async is closed?如何检测通过 boost::asio_stream_async 连接的特定 tcp 流是否已关闭?
【发布时间】:2016-06-14 07:38:13
【问题描述】:

我的C++ library 正在使用 boost::asio_connector_async 列表建立 tcp 连接 问题是,如果由于某种原因关闭了其中一个流,则 boost 不会向我的库发送有关相同的信息。 因此,我的库永远无法检测到哪些流已关闭,哪些仍处于打开状态。 我的库包含一个 boost::asio_connector_async 类的对象(通过连接器的名称)并以这种方式连接到主机、端口:

connector.async_connect(hostname.c_str(), qport.c_str(),          boost::bind(bc::asio_bind_sock_chan<pubsub_channel,pubsub_channel::text_marshaler_registry>(),boost::ref(chan), boost::ref(mar_reg), hostname, qport, channel_logger, _1, _2, _3));

当特定的&lt;host,port&gt; 流关闭时,函数boost::asio_connector_async::on_stream_closed 会从文件asio_stream_async.hpp 内部调用

void on_stream_closed(void * sp, const std::string & host, const std::string port) {
        boost::channel::logger_stream(logger_) << "boost::channel::asio_connector_async::on_stream_closed - " << host << ":" << port << ": stream 0x" << sp << " closed";
      }

我想将我的库附加到boost::asio_connector_async::on_stream_closed,这样每当调用这个特定函数时,我的库中的某些函数也会被调用,以便我的库知道哪个特定流已关闭,然后应该尝试重新连接那条溪流 请建议我怎样才能达到同样的效果?我无论如何都无法在不修改 boost 库的情况下实现这一点(我不应该这样做) 如果有其他方法可以检测关闭的连接,请也向我推荐这些方法。

我是这种网络编程的新手,因此需要相同的帮助。 提前致谢

【问题讨论】:

    标签: c++ sockets c++11 boost tcp


    【解决方案1】:

    需要在您的 handle_read 回调(或您提供的任何名称)中处理客户端断开连接。

    异步读取回调将使用从流中读取的0 字节调用。或者,您也可以检查系统错误代码是否为 asio::error::connection_resetasio::error::eof 或只是简单地 bytes_read == 0(我建议您也进行其他提到的测试。)

    一个示例(来自 asio 示例:chat_client.cpp)

    asio::async_connect(socket_, endpoints,
            [this](std::error_code ec, tcp::endpoint)
            {
              if (!ec)
              {
                do_read_header();
              }
             //ATTN: This is where you should handle failed socket connection
            });
    
    void do_read_header()
      {
        asio::async_read(socket_,
            asio::buffer(read_msg_.data(), chat_message::header_length),
            [this](std::error_code ec, std::size_t /*length*/)
            {
              if (!ec && read_msg_.decode_header())
              {
                do_read_body();
              }
              else
              {
                socket_.close();
              }
            });
      }
    

    async_connect 处理程序中查找ATTN 注释。

    【讨论】:

    • 我不认为 boost/channel/streams/asio_connector_async.hpp::async_conect 采用“错误”参数。 void async_connect(std::string host, std::string port, sock_conn_handler hndl) 我的代码是使用 asio_connector_sync 的对象直接调用 async_connect
    • 我最关心的是将断开连接信息发送到客户端库。当套接字关闭但该信息未与客户端库通信时,Boost 库会检测到断开连接。
    • @ShubhiAgarwal 它是您的处理程序,应该采用 asio::error,而不是 async_connect。在你的情况下sock_conn_handler 。你能告诉我函数sock_conn_handler 的签名吗?
    • sock_conn_handler 也在 boost lib 中定义,而不是我的代码。请参阅下面的 boost 代码: //async_connect template void async_connect(std::string host, std::string port,sock_conn_handler hndl) {..... boost::shared_ptr handler(new conn_handler (hndl));袜子->异步连接(.....)); conn_handler 是 boost::asio_connector_async.hpp 中定义的一个类
    • 调用 async_connect 看起来像这样 connector.async_connect(hostname.c_str(), qport.c_str(), boost::bind(bc::asio_bind_sock_chan(), boost::ref(chan), boost::ref(mar_reg), 主机名, qport, channel_logger, _1, _2, _3));
    【解决方案2】:

    如果检测到连接失败,asio 进行的任何调用都会出错。

    但这并不意味着远程端仍然可以访问。一旦数据被放入内核队列,TCP 发送就完成了。检测到故障可能需要很长时间才能被检测到。

    如果连接保真度很重要,您需要在会话层协议中设计一个回显请求。

    【讨论】:

    • 是否有更直接的方法可以做到这一点,而无需在协议级别进行修改?
    • @ShubhiAgarwal 仅当端点无法发送RST TCP 数据包时才会发生这种情况。通常当端点服务器机器崩溃或突然断电或任何其他原因时。您可以改为使用asio::socket_base::keep_alive ,它会在每次可配置的超时后发送探测数据包。如果它检测到管道损坏,您将再次调用读取处理程序,并设置我在回答中提到的错误。
    • 如果本地链路层断开连接(以太网电缆被拉出),套接字也会出错。如果远程以太网电缆被拉出或中间路由器死机,您将不会收到通知。
    • 谢谢你们。我有一些关于keepalive 的问题: 1. 是否会在我从客户端建立的每个套接字连接上设置此选项(对于每个主机、端口)? 2. 在 boost 库本身中创建了套接字。我将 ioservice 传递给 boost,并且在那里创建了套接字。当我无权访问套接字对象时,如何设置keepalive?
    猜你喜欢
    • 2013-12-31
    • 2012-12-23
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多