【问题标题】:Why does accept() block, when listen() is the very first involved in TCP?为什么accept() 阻塞,当listen() 是第一个参与TCP 的时候?
【发布时间】:2021-04-17 17:18:19
【问题描述】:

accept() 阻塞,直到建立另一个连接并返回 sockfd 才能使双方通信。但是为什么accept() 会阻塞,而首先要做的是三次握手。握手不是由accept() 完成的,而是由listen() 完成的。所以我希望listen() 阻止而不是accept(),因为它首先涉及 TCP。我知道内核对传入连接进行了一些排队,但涉及的第一个函数仍然是listen(),然后连接在队列中向前移动到accept()。因此,当我进行第一次连接时,listen() 将执行 3whs,并且服务器在accpet() 中阻塞。所以另一个连接不能再做3whs,因为服务器没有返回listen(),3whs是哪个?或者为什么accept() 阻止而不是listen()

【问题讨论】:

  • @Carcigenicate 我没有说任何关于改变listen()函数的行为(所以它不会connfd返回为accept()),它只会像往常一样处理连接到accept()。但是 accept() 并不是 TCP 中涉及的第一个函数,就像 listen() 那样。这对我来说没有意义
  • 正如我所说,监听会阻塞,新连接到达,2whs 完成,该过程将跟随接受()。功能与现在相同,但与新连接的第一次接触将是侦听而不是接受,因为接受执行 3whs。所以在当前模型中,这对我来说没有意义,因为如果接受 blocs,新连接不能做 3whs,因为它会听而不接受

标签: linux sockets listen


【解决方案1】:

listen()accept() 是两个完全不同的操作。您对它们的工作原理的理解是错误的。

listen()只是设置监听socket的backlog并打开绑定端口,客户端就可以开始连接socket了。那个打开是一个非常快的操作,不用担心它会被阻塞。

listen() 不执行 3 次握手。当客户端尝试连接到打开的端口并被放入侦听套接字的积压中时,它由内核执行。每个新的客户端连接都会执行自己的 3 次握手。

一旦客户端连接完全握手,该连接就可供accept() 使用以从积压中提取它。仅当新的客户端连接可用于后续通信时,accept() 才会阻塞(或者,如果您使用非阻塞侦听套接字,accept() 会成功)。

您只调用listen() 1 次,打开侦听端口,仅此而已。然后,您必须为要与之通信的每个客户致电 accept()。这就是为什么accept() 会阻止而listen() 不会。

【讨论】:

  • 如果内核执行 3whs,那么什么时候?是在监听和接受的调用之间完成,还是在接受时完成,或者什么时候完成?
  • 内核可以在端口打开的任何时候做2whs?听完之后是哪个?
  • 是的,在listen()退出后的任何时间都可以进行3次握手。但是如何管理握手取决于内核。当一个新连接到达时,一些内核会立即完成 3 次握手,并将连接放入一个单独的队列中,以便 accept() 从中提取。一些内核只执行部分握手,然后仅在实际调用 accept() 时完成。
  • 但是,你真的不需要关心这些细节,内核会为你处理它们。您需要关心的只是调用listen() 来打开所选端口,并调用accept() 来接收来自它的连接。其余的在幕后为您处理。如果您不希望 accept() 阻塞您的代码,请将其移至工作线程,或使用非阻塞侦听套接字。
  • 这不是 3whs 时间的答案。你说它做内核,但你自己不知道它什么时候做的
猜你喜欢
  • 2016-12-09
  • 1970-01-01
  • 2013-05-28
  • 2013-02-19
  • 2011-09-09
  • 2019-09-04
  • 1970-01-01
  • 2015-04-27
  • 2013-05-14
相关资源
最近更新 更多