TCP 握手中,怎么理解从 LISTEN 转换到 SYN_SENT?

2021-12-18 22:08:51 +08:00
 amiwrong123

正常情况下,是上图这样的。就不会有 LISTEN 转换到 SYN_SENT 。

但是好像也存在从 LISTEN 转换到 SYN_SENT 的。 我简单画了个图,不知道下面这样对不对。( https://www.zhihu.com/question/50200176

但我看到书中有这么一句话,就是说,只有 LISTEN 状态下的套接字才可以接受到 SYN 报文段。

那我就有个疑问了,我理解 客户端那边是不会有 LISTEN 状态的套接字的,那么客户端怎么能接受到 服务器发来的 SYN 报文呢

1935 次点击
所在节点    程序员
5 条回复
choury
2021-12-18 23:59:01 +08:00
给你个关键字 tcp 打洞
TomChaai
2021-12-19 00:40:24 +08:00
因为两边可以理解为不是同一条 TCP 连接,客户端先建立一个 TCP 要求服务器开始个业务,服务器反而转变为客户端,尝试把原来的客户端当作服务器尝试建立另一个连接。
这是应用层的设计导致传输层状态变化的例子,不能简单从传输层理解。
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 ,随着时间推移,已经被淘汰了。

我甚至都不知道转换代码要怎么写,也没从看到过案例。
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 。
Caturra
2021-12-19 13:58:21 +08:00
https://www.rfc-editor.org/rfc/pdfrfc/rfc793.txt.pdf

状态转移可以看 PDF 第 29 页(原文 Page23 )

我觉得不应该看它是客户端还是服务端,而是他现在处于什么状态,能处理什么行为

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/823043

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX