【问题标题】:Understanding BSD interface了解 BSD 接口
【发布时间】:2011-06-29 20:16:50
【问题描述】:

我试图了解 BSD 套接字接口中的事件如何转换为 TCP 连接的状态。特别是,我试图了解连接过程的哪个阶段accept() 在服务器端返回

  1. 客户端发送SYN
  2. 服务器发送 SYN+ACK
  3. 客户端发送 ACK

accept() 会在哪一个步骤中返回?

【问题讨论】:

    标签: linux networking tcp


    【解决方案1】:

    accept 在连接完成时返回。 在客户端发送他的 ACK 后连接完成。

    accept 为您提供了一个可以通信的套接字。当然你知道,在建立连接之前你不能通信。并且在握手之前无法建立连接。

    在客户端感知到他的 ACK 之前返回是没有意义的。在最初的 SYN 之后,他完全有可能不会说任何话。

    【讨论】:

    • 其实TCPallowsrequires?需要重新检查RFC793)在收到SYN后调用一个USER接口,让服务器决定是否它想继续握手,或者当场拒绝连接。 BSD 接口没有此 USER 接口(恕我直言,这是有充分理由的),并且该功能由数据包过滤器提供。
    • Linux 中 BSD 套接字的行为在 Linux 2.2 中有所改变。 accept() 将在有完全连接的套接字时返回(而不是在连接完成时)。
    • @ninjalj 好点。实际上,有一些实现允许您为接受(winsock)指定过滤器。 BSD 套接字不这样做 IIRC。
    【解决方案2】:

    内核中的 TCP/IP 堆栈代码通常[1] 完全完成三次握手,无需任何用户空间代码的干预。您列出的三个步骤都发生在accept() 返回之前之前。事实上,它们可能发生在 accept() 甚至被调用之前!

    当你告诉堆栈listen() 用于特定 TCP 端口上的连接时,你传递了一个 backlog 参数,它告诉内核它可以代表你的程序一次静默接受多少个连接。当内核自动接受新的连接请求时,正是这个队列被使用,并且它们被保留在那里直到你的程序得到accept()ing它们。当您调用accept() 时,当listen backlog 队列中有一个或多个连接时,所发生的一切就是将最旧的连接从队列中删除并绑定到一个新的套接字。[2]

    换句话说,如果你的程序调用listen(sd, 5),然后进入一个无限的无操作循环,因此它永远不会调用accept(),从客户端的角度来看,五个并发的客户端连接请求将成功。第六个连接请求将在第一个 SYN 数据包上停止,直到拥有 TCP 端口的程序调用 accept() 或其他客户端之一断开其连接。


    [1] 当然,防火墙和其他堆栈修改可以改变这种行为。我在这里只说默认的 BSD 套接字堆栈行为。

    [2] 如果调用accept()时没有等待在backlog中的连接,则默认阻塞,除非监听套接字设置为非阻塞,在这种情况下它返回-1并且errnoEWOULDBLOCK.

    【讨论】:

      猜你喜欢
      • 2010-11-05
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      • 2018-12-09
      • 1970-01-01
      • 2014-11-21
      • 2013-02-08
      • 2021-02-04
      相关资源
      最近更新 更多