关于网络套接字编程中的listen()、accept()(三次握手)

8
在网络套接字编程中,我知道listen()和accept()的作用。
但是,我想知道的是,在TCP中,三次握手发生在哪里。
是listen()执行三次握手,还是accept()?
我的意思是做syn(客户端)// syn / ack(服务器)// ack(客户端)数据包。
答案:三次握手发生在accept()中。当客户端发送SYN时,服务器通过accept()接受连接并发送SYN-ACK响应,然后客户端再发送ACK来建立连接。

listen()accept()都不是TCP(或任何其他支持的协议)的直接接口。当然,Danny_ds是正确的,listen()必须在执行任何握手之前返回(或能够返回),但这并不意味着系统在建立连接之前等待accept()调用。 - John Bollinger
2个回答

20

一旦应用程序调用 listen(),TCP 栈将为任何传入的连接执行 3 次握手。这些连接在内核中排队,accept() 然后从队列中检索下一个连接并返回它。

listen 函数有一个 backlog 参数,它指定此队列应该有多大(尽管我认为某些实现会忽略这个参数,并使用内置于栈中的限制)。当队列已满时,栈将不再为传入的连接执行握手;客户端应重试,只有在队列有空间时,它们的连接才能成功。

采用这种方式是为了确保客户端在正常情况下(当 backlog 队列有空闲位置时)尽快收到 SYN/ACK,这样它就不必重新传输 SYN


如果没有进行三次握手(我是指客户端发送RST之类的),那么连接就不会排队在后备队列中?只有在队列中存在完美的三次握手,Accept()才会返回新的套接字? - A.Cho
没错。正如其他答案中所示的图表,accept()在3次握手完成之前不会返回。他只是关于accept()触发握手的第二步是错误的。 - Barmar
@Barmar 你确定accept()系统调用不会在服务器端触发SYN + ACK吗?这个网站说accept()负责发送SYN + ACK https://www.ibm.com/developerworks/aix/library/au-tcpsystemcalls/#connect - Zephyr
2
@Zephyr 我确定我是正确的。编写一个调用listen()但从未调用accept()的服务器,然后在客户端连接到端口时进行数据包捕获。我没有看到该网站上哪里说accept()发送了SYN/ACK - Barmar
它说:服务器在处理SYN后,使用tcp_output()ip_output()if_output()序列发送一个SYN ACK数据包。没有关于accept()触发这个过程的内容。 - Barmar
@Barmar 是的,你说得对。我有点混淆了,认为 accept 负责调用 tcp_output(),因为它们在同一个图表中。 - Zephyr

0

listen()是用于监听服务器收到的请求的。

当有请求时(假设我们使用TCP,如果你使用UDP则不会使用listen或accept,因为它不像TCP那样是面向连接的协议),则会进行TCP的三次握手。如果服务器正在处理请求,则该请求将被移至队列中。队列的大小可以指定,挂起请求的最大数量取决于操作系统,然后还有另一个队列接受函数,每次调用listen时从中取出请求,然后返回新套接字以用于此连接和(地址、端口)给listen()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接