【问题标题】:SOCK_STREAM socket listen() causing TCP syn/ack to be sentSOCK_STREAM socket listen() 导致发送 TCP syn/ack
【发布时间】:2012-10-26 23:52:08
【问题描述】:

我设置了一个套接字来接受 TCP 连接

socket(AF_INET, SOCK_STREAM, 0)

然后我打电话给bind()listen()accept()

问题是当我调用listen() 时,它会导致向客户端发送一个SYN/ACK 数据包。我以为直到我调用了 accept() 才会发生这种情况,但更糟糕的是 SYN/ACK 数据包没有确认增加一。

这是什么原因造成的,我该如何解决?

谢谢

附带说明 - 我的 TCP 连接不对称是否重要?

【问题讨论】:

  • 如果这是主流的 TCP 实现,不太可能是行为不端。客户端是否在服务器调用 listen() 之前尝试连接?如果是这样,并且它没有超时,那么可能有点不寻常(但绝不是非法)的事件顺序意味着正确的行为与您的预期有些不同。
  • 嗯,确实如此。我实际上是在拦截一些流量,并在客户端尝试连接之后(客户端是 wget)站起来监听()。这有点像我正在尝试实现的即时端口转发
  • 发布一个导致问题的最小示例。
  • @Derek 你看起来很困惑。通常每个接受的套接字都有一个线程,即每个客户端,所以没有什么可以混淆的。
  • 所以你仍然需要每个套接字一个线程,也许两个,一个读,一个写。或者可能使用 poll()。您当然不希望多个线程写入同一个套接字:交错可能以任何方式发生。你所知道的是,每个 send() 都是原子的,即所有数据都放在一起。

标签: c sockets network-programming freebsd


【解决方案1】:

在您调用listen 时,您机器上的 TCP 实现可能会选择实际“接受”传入连接。这实际上是有道理的,以避免由于“懒惰”接受而导致不必要的延迟。提醒一下,listen 的参数之一就是所谓的积压数,即“缓冲”接受待处理的数量。

关于syn+ack数据报中ACK的递增。我不记得协议规定了什么,但这可能是握手期间的正确行为。

【讨论】:

  • 我同意增加它的正确行为。我只是一直认为它发生在连接的“接受”阶段。
  • @Derek 它确实发生在连接的“接受”阶段,但该阶段通常发生在应用程序调用 accept() 函数之前。
【解决方案2】:

这是 TCP 'backlog' 队列的正常操作。它是堆栈已经完成但应用程序尚未接受的连接队列。此队列的大小由 listen() 的第二个参数设置,尽管平台可以向上或向下调整它(通常是向上)。

您观察到的有关序列号的任何行为也必然是正确的行为,否则将无济于事。

【讨论】:

  • 如果积压队列设置为零,这是否会强制内核等待接受某些内容,直到我准备好隐式调用 accept()?
  • @Derek 不。内核会默默地强制执行它的最小值,可能是 5 或 500。你为什么想要零?
【解决方案3】:

正如其他答案和 cmets 中提到的,这是 TCP 实现的实际标准行为。

如果您坚持通过接受应用程序中的传入连接来明确完成 TCP 握手,则您有平台相关的解决方案。

对于 Windows 堆栈,您可以在侦听套接字上设置 SO_CONDITIONAL_ACCEPT 套接字选项。见winsock documentation

【讨论】:

    猜你喜欢
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-05
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多