正常情况下,是上图这样的。就不会有 LISTEN 转换到 SYN_SENT 。
但是好像也存在从 LISTEN 转换到 SYN_SENT 的。 我简单画了个图,不知道下面这样对不对。( https://www.zhihu.com/question/50200176 )
但我看到书中有这么一句话,就是说,只有 LISTEN 状态下的套接字才可以接受到 SYN 报文段。
那我就有个疑问了,我理解 客户端那边是不会有 LISTEN 状态的套接字的,那么客户端怎么能接受到 服务器发来的 SYN 报文呢
1
choury 2021-12-18 23:59:01 +08:00 via Android
给你个关键字 tcp 打洞
|
2
TomChaai 2021-12-19 00:40:24 +08:00
因为两边可以理解为不是同一条 TCP 连接,客户端先建立一个 TCP 要求服务器开始个业务,服务器反而转变为客户端,尝试把原来的客户端当作服务器尝试建立另一个连接。
这是应用层的设计导致传输层状态变化的例子,不能简单从传输层理解。 |
3
3dwelcome 2021-12-19 01:12:35 +08:00
那个知乎的 FTP 回答有问题,我去 GITHUB 查了代码,有看到:
Serv-U FTP Server v6.3 on PORT command, the client listen on a port and wait the server to connect. on PASV command, the server listen on a port and wait the client to connect. 说明在 FTP 里,服务器去反向连接客户端,并不是 listen socket 的内置状态切换,而是就是普通的客户端 listen 监听,服务端 connect 连接罢了。 可能早期 TCP/IP 协议里有设计 LISTEN 转换到 SYN_SENT ,随着时间推移,已经被淘汰了。 我甚至都不知道转换代码要怎么写,也没从看到过案例。 |
4
sisylocke 2021-12-19 01:29:10 +08:00
我不同意这是应用层的设计导致的问题,这些差别就是 TCP 协议的不同实现。
首先你的图客户端和服务端是不是弄反了,一般把被动打开的一方称为服务端,主动的一方称为客户端。 在建立 TCP 连接的时候,客户端和服务端各自都需要初始化一个控制块( TCB ),根据 RFC793 的建议的标准做法,这个连接的初始状态就是 Listen 。但是在具体实现的时候就会发现这一步是多余的。客户端在初始化 TCB 后发送 SYN ,然后状态立即变为 SYNSENT ;服务端接收 SYN 请求,然后初始化一个 TCB 后,状态又立即变为 SYN-RCVD 。所以 Listen 状态是一个很短暂的状态,完全可以一步到位将 TCB 初始化为 SYN 或者 SYNRCVD 状态。 所以在新连接的时候一般不会出现 LISTEN 状态,但是不是说 LISTEN 状态就没用了。当接受到 RST 的时候,并不一定代表对方是关闭连接,所以有的 TCP 实现并不会直接丢弃这个连接,而是重新初始化 TCB 等待重新握手恢复连接,这时的状态就是 LISTEN 。 |
5
Caturra 2021-12-19 13:58:21 +08:00
https://www.rfc-editor.org/rfc/pdfrfc/rfc793.txt.pdf
状态转移可以看 PDF 第 29 页(原文 Page23 ) 我觉得不应该看它是客户端还是服务端,而是他现在处于什么状态,能处理什么行为 |