TCP协议(一)

TCP协议

TCP 是传输层中的协议。

包头格式

特点

  • 面向连接。客户端与服务端都需要建立一定数据结构来维护双方的状态
  • 提供可靠交付。无差错、按顺序、不重复、不丢失,尽最大努力传送
  • 面向字节流。传送的数据并不是完整有头有尾的内容,而是按字节计算的
  • 可以流量控制。发送方根据接收方的接收能力调整发送速度
  • 可以拥塞可控制。根据网络情况调整发送的速度

三次握手

TCP 的连接与包头中的信号位序号确认序号有关。以下是一次 TCP 三次握手连接的客户端与服务器的状态时序图。

  1. 发送一个 SYN 被置为1ACK0的请求则视为连接请求
  2. 如果对方同意连接,则在应答报文中将 SYNACK 都置为1
  3. 请求方收到应答报文后,会再发送一个应答报文给对方

TCP 规定在连接建立后的所有传输报文都必须把 ACK1

经历上述三次握手后,才算是个完整的 TCP 连接。下图是使用 wireshark 抓取的 TCP 三次握手数据包。

为什么是三次握手

可靠的连接就是双方都可到达对方。为什么需要三次,而不是两次?按理说,两个人说话,你一句我一句这对话算是对上了?为了可靠,那为什么不是四次?

两次握手

A 发送请求给 B,B 发送应答给 A,就完成了两次握手,双方建立连接。

会出现的问题:

  • A 发送请求给 B,B 发送应答给 A,然后 A 挂了,B 懵了
  • A 发送请求给 B,因为网络不好,A 没收到 B 的应答,继续尝试发送请求包。终于收到应答包,两人愉快通信,然后关闭连接。这时,A 上次尝试发送的请求包绕路回来了,B 一看,美滋滋应答了,但是 A 并没打开连接,所以 B 就会懵了

所以两次握手不可靠。

四次握手

第三次握手是为了解决 B 是否真的可以建立连接状态,需要有 A 的回应。那有小朋友就问了,那第三次没握上怎么办?

其实对于 A 来说,在第二次握手后即收到 B 的应答后,就可以进入连接状态了,因为对于 A 发送的消息是有回应的。即使第三次握手的数据包丢失了,B 没有收到 A 发送的应答,但是在大部分情况下 A 在进入连接状态后会马上发送数据,到达 B 后,B 就可以认为这个连接已经建立。

消息有来有回

还有情况是,A 连接后不发送数据,开启 keepalive 机制,但是即使没有真实的数据,也有探活包。对于 B,可以主动关闭不发包的客户端。

包序号的问题

三次握手除了建立连接,还有沟通包的起始序号的作用。下图为客户端发送 TCP 数据包的 wireshark 抓包截图。

  • 每次连接的起始序号是随时间变化的计数器,每4微秒加一。为了避免遇到上一次连接的包,而错误接收
  • 第二个包的序号为起始序号加一
  • 其他包的序号为上一个序号加 TCP payload 的字节长度

四次挥手

简单来说,TCP 的报文传输是需要有回应的,A 发送带关闭位 FIN 请求给 B 后,B 回应 A,就算两次挥手。因为 B 是被通知的一方,总是有可能会有些事情没有处理完而不能关闭,所以 B 可以关闭时,发送关闭请求 FIN 给 A,而 A 也需要回应,总共就四次挥手。

当进入 FIN_WAIT 状态后,如果对方没有响应,在 Linux 中可以设置 tcp_fin_timeout 这个参数确定超时时间。TIME_WAIT 是为了等待对方没有收到回应而再发送 FIN 时可以做出回应,还有确保下个使用该端口的应用不会收到还在路上未到的包,简单来说就是等待包都超过最大生存时间(MSL)。

我断开你知道,你断开我知道,你知道『我知道』


参考

2019-2020 shens3