三次握手
tcp三次握手目的是确认双方的初始序列号(ISN,Initial Sequence Number)。
序列号按字节累加。其作用是:
- 数据包排序:序列号使接收方能够重新排序因网络拥塞、重传等原因而乱序到达的数据包,确保数据可以按正确的顺序被处理和重组。
- 数据完整性:通过检查序列号,接收方可以发现丢失的数据包,从而请求重传丢失的数据,确保数据的完整性。
- 避免旧连接的数据干扰:使用唯一的初始序列号可以防止来自旧连接(具有相同源和目的IP地址及端口的连接)的延迟数据包被错误地认为是新连接中的数据。
四次挥手
tcp四次挥手:因为tcp是双向传输数据的信道,所以需要发四次消息关闭双方各自的信道。
需要注意的是,主动发起关闭的一方(可以是客户端可以是服务端)最后会处于一段时间的TIME_WAIT状态,时长为2MSL(最大报文段生存时间的两倍)。linux中一般默认TIME_WAIT状态的持续时间是2分钟。
这个持续时间很长,如果服务端程序有问题,频繁关闭客户端的tcp连接。而客户端又会尝试重新建立新的连接。如此循环往复,会导致服务器上存在大量处于TIME_WAIT状态的tcp连接。在linux中每个tcp连接都会占用一个文件描述符,而每个进程都会有一个文件描述符上限,一般默认为65535个。如果达到这个上限就会报错,且无法创建新的tcp连接。
如果客户端频繁建立和关闭tcp连接(大量使用短连接),则最有可能由于端口耗尽而无法创建新的tcp连接。
tcp报文格式
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+