Client ------SYN-----> Server
Client <---ACK/SYN---- Server
Client ------ACK-----> Server
ACK, acknowledge, 美 [əkˈnɑlɪdʒ] v. 承认;认识;确认
SYN, synchronize, 美: ['sɪŋkrə.naɪz] v.(使)同步
handshake 美: ['hæn(d).ʃeɪk] 握手
其实是4次的
客户端向服务器建立通信需要一来一回, 即两次(请求和回应)
客户端 → 服务器, 服务器 → 客户端
服务器向客户端建立通信也需要一来一回, 这就四次了
服务器 → 客户端, 客户端 → 服务器
服务器向客户端回应时, 可以同时请求, 这就由四次变成了三次
同样的TLS 握手时也可以在客户端回应服务器时同时展开
本来时8次互动, 变成了5次
HTTP/3 甚至把8次合并成了3次
https://networkengineering.stackexchange.com/questions/24068/why-do-we-need-a-3-way-handshake-why-not-just-2-way
TCP 是双向通信
TCP 是会补包的协议
需要互相确定初始序列号
ISN, Initial Sequence Number, 初始序列号
A -> B 我的初始序列号是X
A <- B 我知道了, 我等着接收X++
A <- B 我的初始序列号是Y
A -> B 我知道了, 我等着接收Y++
TCP A TCP B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> --> SYN-RECEIVED
3. ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
4. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHED
5. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED
Basic 3-Way Handshake for Connection Synchronization
TCP A TCP B
1. 没有连接的状态 监听请求的状态
2. 发送连接请求 --> <SEQ=100><CTL=SYN> --> 收到值并+1
3. 收到值并+1 <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- 确认收到, 发送连接请求
A 在第二步发送了100, B 返回了101
A 发送数据的起始序列号就是101
4. 确认收到 --> <SEQ=101><ACK=301><CTL=ACK> --> 已连接
5. 已连接 --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> 已连接
假设发送数据920字节
5. 已连接 --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> 已连接
Basic 3-Way Handshake for Connection Synchronization
为什么初始序列号不统一从0 开始?
https://tools.ietf.org/html/rfc793#section-3.3
预测TCP 序列号的攻击, 使得接收方收到假数据导致真正数据无法处理
https://en.wikipedia.org/wiki/TCP_sequence_prediction_attack
避免与新的连接冲突
连接关闭, 仍有数据在路上没到目的地
新连接建立, 旧数据到达目的地, 序号相同, 造成混乱
初始序列号是随机的, 32个二进制位, 0~4294967295之间的任何值
如何确认数据包有没有丢失
每次发送数据n个字节, 根据数据的大小增加序列号的值
发送方把序列号加上数据的字节数后, 把序列号发过去
发送完所有的数据, 或者一批数据后等待服务器确认相应
比如设定数据大于5000字节就要分批等待确认后再发剩下的
服务器会像握手时那样把序列号+1 后发过来
根据服务器给的序列号继续发送数据