【问题标题】:Does connect() block for TCP socket?TCP 套接字的 connect() 是否阻塞?
【发布时间】:2012-01-05 16:25:54
【问题描述】:

您好,我正在阅读 TLPI(Linux 编程接口),我有一个关于 connect() 的问题。

据我了解,如果 listen() 的挂起连接数未达到“积压”,connect() 将立即返回。 否则它会阻塞。 (根据图56-2)

但是对于 TCP 套接字,它会一直阻塞,直到服务器端的 accept() 被调用(根据图 61-5)。

我说的对吗? 因为我在示例代码 (p.1265) 中看到,它调用 listen() 来监听特定端口,然后在调用 accept() 之前调用 connect() 到该端口。

所以在这种情况下 connect() 会永远阻塞,不是吗?

谢谢!!

【问题讨论】:

  • 如果图 56-2 真的是这样,那就错了。

标签: c linux sockets


【解决方案1】:

connect() 阻塞直到完成 TCP 3 次握手。侦听端的握手由内核中的 TCP/IP 堆栈处理,并在不通知用户进程的情况下完成。只有在握手完成后(并且发起者已经可以从 connect() 调用返回),用户进程中的 accept() 才能获取新的套接字并返回。完成握手不需要等待 accept()。

原因很简单:如果你有单线程进程监听连接并且需要等待accept()来建立连接,你在处理另一个请求时不能响应TCP ​​SYN。发起端的 TCP 堆栈将重新传输,但在中等负载的服务器上,这个重新传输的数据包仍然会到达,而没有 accept() 挂起并且会再次被丢弃,从而导致严重的延迟和连接超时。

【讨论】:

    【解决方案2】:

    几乎没有关于网络的“立即”,东西可能会在途中丢失,理论上应该立即执行的操作在实践中可能不会这样做,并且无论如何都有端到端的传输时间。

    然而

    • TCP 套接字上的connect() 是阻塞操作,除非套接字描述符被置于非阻塞模式。

    • 操作系统负责 TCP 握手,当握手完成时,connect() 返回。 (那是, connect() 直到另一端调用 accept()) 才会阻塞

    • 成功的 TCP 握手将排队到服务器应用程序,并且可以在以后的任何时间接受()。

    【讨论】:

    • 只是想补充一下connect只是等待握手而不是服务器调用accept,原因有两个:首先是从客户端连接他之后握手;第二个是因为握手之间可以通过任意时间,在服务器调用accept之前,这确实可以是永远的。
    • 即使没有其他答案,“几乎没有任何'立即'”单独保证+1。对于很多操作来说都是如此,即使在非阻塞模式下也是如此。有时,立即可能会令人惊讶很长时间,即使对于您真的没想到的事情也是如此。
    • @JoachimPileborg @nos 如果connect() 在服务器调用accept() 之前返回,如果客户端在服务器调用accept() 之前尝试send() 会发生什么?
    • @Andrew 数据由接收系统网络堆栈缓冲,直到缓冲区已满,在这种情况下接收网络堆栈将回复一个空窗口,导致发送方从@返回987654328@ 调用出错。
    • @Andrew 如前所述,没有“立即”。通过网络完成握手可能需要很多(数百)毫秒。在那段时间里,你可以做数以百万计的事情,比如等待(阻塞)握手完成。
    【解决方案3】:

    connect 默认情况下是一个阻塞调用,但您可以通过将SOCK_NONBLOCK 标志传递给socket 使其成为非阻塞调用。

    【讨论】:

    • 或者更常见的是,使用 fcntl 的“传统”BSD 套接字函数和 O_NONBLOCK。 SOCK_NONBLOCK 是特定于 Linux 的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 2019-02-06
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    • 2013-10-15
    相关资源
    最近更新 更多