【问题标题】:Active close vs passive close in terms of socket API?就套接字 API 而言,主动关闭与被动关闭?
【发布时间】:2016-08-25 17:46:19
【问题描述】:

在 TCP 中,我们说连接的一侧执行“主动关闭”,另一侧执行“被动关闭”。

在 Linux 套接字 API 方面,如何区分主动关闭和被动关闭?

例如,假设我们有两个连接的 Linux TCP 套接字 A 和 P,它们通过应用程序级协议交换了信息,并且它们都知道是时候关闭它们的套接字了(都不希望发送或接收任何彼此之间的更多数据)。

我们希望套接字 A 执行主动关闭,而 P 是被动关闭。

A 和 P 可以做一些事情。例如:

  • 调用关机(SHUT_WR)
  • 调用 recv 并期望得到 0 回复
  • 通话结束。
  • 别的东西

这些东西的什么组合和A应该做的顺序?...这些东西的组合和P应该做的顺序是什么?

【问题讨论】:

  • BOTH A 和 P 应该执行 ALL 您提到的步骤:shutdown(SHUT_WR),然后循环 recv() 直到它返回 close()。执行这些步骤的第一方开始关闭,然后另一方一旦检测到关闭就应该执行相同的步骤,因此双方都知道连接的两端都已正常关闭。
  • @RemyLebeau:所以没有办法控制哪一边是主动关闭,哪一边是被动?
  • 没有真正的“主动”与“被动”接近。一方可能会被动地检测到另一方的关闭,但双方仍然需要关闭他们的连接端。但是,有“优雅”与“中止”关闭之类的东西,这取决于是否调用了shutdown() 以及是否在套接字上启用了 linger。你应该尽可能地争取优雅的结束。
  • @RemyLebeau “主动关闭”和“被动关闭”是已经使用了几十年的流行术语。像许多其他特定年龄的 C 程序员一样,我从 W. Richard Stevens UNIX 网络编程 那里学到了它,但我确信它们甚至早于他的使用。但是,这并不能否定您所说的其他任何内容。当然,连接的双方都应该在情况允许的情况下优雅地关闭。
  • @AndrewTomazos 双方都必须关闭。第一个这样做是“主动关闭”(使用我也不喜欢的术语),这可能由您的应用程序协议定义,出于其他原因,最好是客户端而不是服务器,但从简单终止连接的角度来看,它是无关紧要的。

标签: c linux sockets tcp


【解决方案1】:

就 Linux 套接字 API 而言,您如何区分活动的 关闭和被动关闭?

“主动”关闭只是套接字的任何一侧首先发送FINRST 数据包,通常通过调用close()

这些事情的什么组合以及A应该以什么顺序做?...和 这些东西的组合,P应该按什么顺序做?

实际上,其中大部分是特定于应用程序和应用程序协议的。我将描述回答您问题的最低/典型要求,但您的里程可能会有所不同,具体取决于您具体要完成的任务。

可以首先在 Socket A 上调用 shutdown(),如果您想终止 Socket A 上的一个方向或另一个(或两者)的通信。根据您的描述,两个程序已经知道它们重新完成,可能是由于应用程序协议消息,所以这可能没有必要。

必须在 Socket A 上调用 close() 以关闭套接字并释放文件描述符。

在 Socket P 上,您只需继续阅读直到 recv() 返回 0,然后您必须调用 close() 来关闭套接字并释放文件描述符。

为了进一步阅读,那里有很多很好的教程,Beej's Guide to Network Programming 很受欢迎。

【讨论】:

    【解决方案2】:

    主动打开是当您明确发出connect(2) 以建立与远程站点的连接时。调用阻塞,直到您在另一侧打开套接字(除非您在调用 connect(2) 之前发出 O_NONBLOCK fcntl(2) 调用。

    被动打开是当您有一个套接字listen(2)正在连接并且您尚未发出accept(2)系统调用时。 accept(2) 调用通常会阻塞,直到您有一个完全打开的连接并为您提供一个套接字描述符以通过它进行通信,或者如果在您发出 accept(2) 系统调用时连接握手已经完成,则立即为您提供一个套接字描述符(这是被动打开)。当您准备进行accept(2) 系统调用时,内核可以代表您接受的被动打开连接数的限制就是所谓的listen(2) 值。

    主动关闭是当您显式调用shutdown(2)close(2) 系统调用时发生的情况。与被动打开一样,您无法进行被动关闭(这是在幕后发生的事情,是对方行动的产物)。当套接字生成 文件结束 条件(即,read(2) 总是在读取时返回 0 字节)时,您检测到 被动关闭,这意味着 另一个end 已完成shutdown(2)(或close(2)),连接一半(或完全)关闭。当您明确地shutdown(2)close(2) 您身边时,它是一个主动关闭。

    注意

    如果另一端做了一个显式的close(2) 并且你继续在套接字上写,你会因为无法发送数据而得到一个错误(在这种情况下我们可以讨论一个被动的close(2) ---在我们这边没有任何明确行动的情况下发生),但另一端可以调用shutdown(2) 进行半关闭。这使得 tcp 仅发送FIN 段并保存套接字描述符以允许线程接收任何正在传输或尚未发送的未决数据。只有当它接收并确认另一端的FIN 段时,它才会向您发出没有更多数据仍在传输中的信号。

    【讨论】:

    • “被动打开是当你有一个套接字监听(2)连接时”是正确的。该段的其余部分不是。 “被动打开”是指监听套接字本身。第一段的其余部分是关于accept() 进程的,当你调用accept() 时,积压队列中是否已经存在连接基本上与accept() 是否阻塞无关。
    • @EJP,是的,这无关紧要,但是要知道是否发生了被动连接,您必须执行accept(2) 系统调用,和/或至少检查如果它应该阻止。由于您永远无法获得连接的套接字,因此只能通过accept(2) 系统调用,没有其他非特权方法可以从套接字接口知道发生了被动连接。根据定义,被动的事情发生在没有进程/线程的主动参与的情况下,那么你怎么知道被动连接是否发生了呢?该段落是对问题的解释,即使与主动/被动连接无关。
    • @EJP,是的,还有另一种方法可以知道在listen(2)accept(2) 系统调用之间是否发生了连接:在侦听套接字中读取select(2),但是正如你所说,该段落并没有错。
    猜你喜欢
    • 2011-05-08
    • 1970-01-01
    • 2013-01-22
    • 2014-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    相关资源
    最近更新 更多