【问题标题】:keep_alive options for boost tcp acceptor and boost tcp socketboost tcp 接受器和 boost tcp 套接字的 keep_alive 选项
【发布时间】:2016-11-05 05:11:02
【问题描述】:

我有几个问题,都与keep_alive有关。

  • basic_socket_acceptor::keep_alivebasic_stream_socket::keep_alive 有什么区别?什么时候用哪个?
  • 我们是否需要为ip::tcp::acceptor 使用任何类型的keep_alive?这对我来说没有意义,因为接受器没有 no 连接,但它也有一个keep_alive option,因此造成了混乱。
  • 如果设置了keep_alive,那么Boost Asio 检测到连接断开时的行为是什么?它如何/何时通知用户代码?它会抛出异常吗?如果是这样,哪个例外?我在文档中没有看到任何此类详细信息。

【问题讨论】:

    标签: c++ sockets boost tcp boost-asio


    【解决方案1】:

    basic_socket_acceptor::keep_alive 和有什么区别 basic_stream_socket::keep_alive?什么时候用哪个?

    两者都是一样的。在文档中,它出现在basic_socket_acceptorbasic_stream_socket 下,因为两者都派生自socket_base,其中keepalive 选项实际上是可见的(它是一个typedef)。

    根据文档中的示例,您将始终像这样使用它:

    boost::asio::socket_base::keep_alive option(true);
    socket.set_option(option);
    

    我们是否需要为 ip::tcp::acceptor 使用任何类型的 keep_alive?

    不,你不必也不能。 set_option 无论如何只能在套接字对象上调用(我相信只有在套接字是 opened 之后)。

    如果设置了keep_alive,那么Boost Asio的行为是什么? 检测到断开的连接?

    这取决于平台。在 linux 上,当 keep_alive 探测失败时,您将收到 broken pipe 错误或 EPOLLERR/EPOLLHUP

    更新(来自我下面的评论):

    此故障不会传播到用户代码。因此,您可能需要实现应用程序级别的 ping 或使用超时套接字选项。

    【讨论】:

    • “在 Linux 上,当 keep_alive 探测失败时,您会遇到管道损坏错误或 EPOLLERR/EPOLLHUP。”。如果我不显式发送任何keepalive数据包,I(即用户代码)将如何获得任何东西?我相信在设置keep_alive 选项后,底层库会将此类数据包发送给客户端,我可能不知道它何时以及多久发送一次。无论这些问题的答案是什么,我唯一关心的是如何在看到管道损坏时准确地通知用户?我是否需要设置库会调用的任何回调?
    • @Nawaz 可以接收异步 SIGPIPE 信号。 Boost Asio 有 signal_set 你可以使用它。如何将信号与特定套接字关联是您的挑战,但至少这会给您连接断开警报。
    • @Nawaz 我希望你能扩展你的问题,而不是假设我知道或不知道什么。
    • 我明白你在说什么。您可以查看一些在生产中使用 asio 的实现,例如:github.com/ripple/rippled。无论如何,asio 并没有抽象出那么多细节。它的行为应该完全(几乎)像手写的基于epoll 的事件循环,除非你有一些复杂的逻辑,你在代码中执行io_service::stopio_service::reset 之类的东西。
    • 就我使用asio 的经验而言,我确实玩弄了它的代码库,主要是为了好玩,但从来没有用它来将它部署到生产环境中。一旦您开始使用strand 来控制处理程序执行顺序和其他自定义io_object 和服务,事情就会变得有点复杂。 AFAIK,没有太多(或根本没有)博客或文档详细介绍 ASIO 所做的事情,但您始终可以浏览源代码。一旦你理解了作者所遵循的基本模式,你就会对它感到满意。
    【解决方案2】:

    basic_socket_acceptor::keep_alivebasic_stream_socket::keep_alive 是相同的。文档指出,它们都继承自 socket_base 类,该类定义了 socket_base::keep_alive 选项。

    basic_stream_socket::keep_alive

    继承自 socket_base。

    发送keep-alives的套接字选项。

    虽然监听套接字上的保持活动对监听套接字没有直接作用,但在某些系统上,新接受的套接字会从监听套接字继承一些套接字选项。继承的套接字选项通常是会影响必须在accept() 返回之前完成的 TCP 三向握手的选项,例如SO_KEEPALIVE。因此,Asio 支持在接受器上设置 keep-alive 选项;但是,Asio 不会将套接字选项复制到新套接字。

    keep-alive 功能允许写入 操作通知连接已断开,这由keep-alive 机制确定1。因此,当 keep-alive 探测失败时,套接字上的下一个 Asio 写操作将失败2,以与提供其他错误代码相同的方式将 error_code 传递给应用程序。应该查阅操作系统的文档以确定写入操作的预期错误代码:

    • 在 Windows 上,WSASend() 记录为返回 WSAENETRESET (boost::asio::error:: connection_reset)
    • 在 Linux 上,错误将根据保活探测失败的方式而有所不同。如果没有响应,则将出现ETIMEOUT (boost::asio::error::timed_out)。如果响应保持活动探测返回 ICMP 错误,则将返回相关的 ICMP 错误。例如,可以观察到 EHOSTUNREACH (boost::asio::error::host_unreachable) 被返回

    1. 请参阅RFC 1122
    中指定的Internet 主机要求—通信层中的 4.2.3.6 2.SO_KEEPALIVE通过SIGPIPE信号通知线程写入套接字,但Asio明确禁止在写操作时接收SIGPIPE。因此,底层系统调用将返回相关错误

    【讨论】:

      【解决方案3】:

      这取决于您运行的平台。在 linux 上,如果您执行以下操作,

      boost::asio::socket_base::keep_alive option(true);
      socket.set_option(option);
      

      那么您基本上可以免受可能发生的轻微网络中断并导致套接字上的读取或写入错误。如果你在套接字指针上将keep_alive 设置为 true,那么有几种方法可以检测你正在读/写的套接字上的错误:

      • 首先,您可以通过实现在对等方之间间隔发送健康数据包的乒乓机制来检测套接字错误。

      • 或者,当您从套接字返回boost::asio::error::eof 错误时,您也可以检测到错误,这基本上意味着对等方已关闭连接。请注意,如果连接被对等方关闭,则对套接字的读取仍可能返回 boost::asio::error::eof 错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-10
        • 1970-01-01
        • 2012-12-28
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        • 1970-01-01
        • 2020-05-22
        相关资源
        最近更新 更多