计算机网络传输层---TCP连接的建立和终止(详解三次握手四次挥手)
计算机网络传输层—TCP连接的建立和终止(详解三次握手四次挥手)
TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。
TCP的特点:
- TCP提供客户与服务器之间的连接,是基于连接的数据传输协议,因此是一对一的
- TCP提供可靠性,数据可以无差错、不丢失、不重复、按需到达
- TCP提供拥塞控制和流量控制,保证数据传输的安全性
- TCP是全双工的,在一个连接上的任意时刻在进出两个方向上既可以发送数据也可以接收数据
- TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是
20
个字节
TCP的头部格式:
- 源端口和目标端口号:用于多路复用和多路分解来自上层应用的数据
- ***:***是实现可靠性的关键。在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每个数据包都有响应的***,用于标识该数据包,从而实现有序、不重复、重发等机制。
- 确认应答号:指下一次「期望」收到的数据的***,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。也是实现可靠性传输的关键
- ACK:该位为 1 时,表示 确认应答的字段为有效
- RST:该位为 1时,表示 TCP 连接中出现异常必须强制断开连接
- SYN:该位为 1 时,表示是要建立连接,进行初始化***,在其 ***的字段进行***初始值的设定
- FIN:该位为 1 时,表示发送方不再进行数据发送,要断开连接
- 窗口大小:实现流量控制的关键,发送方根据收到的窗口大小的值调整自己的发送速率
- 校验和:由发送端填充,接收端对tcp报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏
TCP三次握手
TCP通过三次握手建立连接,通过三次握手双方确认***、窗口大小等信息
三次握手的流程:
- 客户端向服务器发送一个TCP报文,该报文不包含应用层数据。其中该 报文的SYN位 置为1,然后客户端的操作系统会随机初始化一个***,将该***放置到TCP报文的***字段中。
- 服务器收到该报文后,提取出***报文段,然后为该TCP连接分配缓存和变量,然后向客户端发送一个确认连接的TCP报文。该报文的SYN位 置为1,ACK位 置为1,其中***字段填充服务器生成的随机***,ACK段填充的是客户发的数据包的***+1。该报文不包含应用层数据
- 客户端收到服务器的SYNACK报文后,客户为该连接分配资源。客户端向服务器发送TCP报文,其中ACK置为1,确认应答号为服务器的***+1,***为客户端的***+1.注意SYN位 置为0,该数据包可以携带应用层数据信息。
三次握手建立后双方将处于建立连接状态。
从网络编程的角度再次解析该过程:
- 开始三次握手前,服务器需要处于准备好接收外界连接的状态。因此需要调用socket、bind、listen三个函数,完成套接字的打开、绑定端口、监听,服务器处于被动打开
- 客户通过connect发起主动打开,客户TCP发送一个SYN报文,填充了随机初始化的***,告知服务器该连接的初始***。
- 服务器收到客户端的SYN报文后,需要确认客户的SYN,并发送自己的SYN。因此发送的数据包中有自己随机初始化的SYN,以及对客户SYN的确认ACK(客户的SYN+1)
- 客户收到后将发送ACK确认服务器的SYN
为什么采用三次握手?
- 三次握手可以阻止历史重复连接的初始化 (两次握手没办法避免历史重复连接的干扰)
- 三次握手可以同步双方的初始*** (TCP是全双工,因此同步双方***至少需要三次握手)
- 三次握手可以避免资源浪费
TCP四次挥手
TCP通过四次挥手完全关闭连接并释放资源。值得注意的是,TCP连接的任意一方都可以主动请求终止该连接
四次挥手的过程: 以客户端关闭连接为例
- 客户端没有数据要再发送,想要关闭连接,因此发送一个特殊的TCP报文,该报文的FIN位 置为1,表示是终止连接报文。
- 服务器收到该报文后向客户端发送ACK确认该终止报文已收到,服务器进入
CLOSED_WAIT
’状态 - 此时,该TCP连接中,服务器仍可以向客户端发送数据
- 服务器发送完数据后,也申请终止连接。向客户端发送一个FIN报文,其中FIN 置为1
- 客户端收到后向服务器发送一个ACK表示收到,客户端进入
TIME_WAIT
状态 - 服务器收到ACK后将进入关闭状态,服务器的该连接的资源进行释放
- 客户端经过 2MSL 时间后进入关闭状态, 释放该连接的资源
从网络编程的角度再次分析四次挥手:
- 某个进程首先调用close函数,我们称该端为主动关闭,该端TCP发送一个FIN包,表示数据发送完毕
- 接收到FIN的另一端执行被动关闭,该端返回一个ACK。接收到FIN表示接收端应用进程在该连接上无额外数据可接收
- 一段时间后,另一端发送数据完毕,调用close关闭套接字,因此它也发送一个FIN包
- 接收到这个FIN包的端(主动关闭端)需要发送一个ACK确认该FIN
需要注意的是,在TCP断开连接时,存在一个半关闭状态,即虽然停止了接收数据但是仍然在发送数据。
TCP连接的整体图示:
TCP状态转移图:
在一个TCP连接的声明周期中,运行在每台主机上的TCP协议会在各种状态之间变迁。
客户TCP的典型状态变迁:
服务器端TCP的典型状态变迁:
TIME_WAIT状态
当主动方接收到被动方发来的FIN后,将进入TIME_WAIT状态。TIME_WAIT 状态的时间通常是最长分节生命期(MSL)的两倍,通常称为2MSL。
TCP实现时必须为MSL设置一个值,通常是1分钟到4分钟左右,MSL是任何IP数据报能够在因特网中存活的最长时间。
为什么需要 TIME_WAIT 状态?
- 可靠地实现TCP全双工连接的终止(假如回复的ACK服务器没有收到,但是自己已经关闭连接,则服务器将一直发送FIN直至一些机制触发导致自己关闭,这将浪费服务器资源,使其无法正常关闭。为了正确终止连接,必须正确处理终止序列中4个分节任意一个分节丢失的情况)
- 允许老的重复分节在网络中消逝 (经过两个MSL,足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的,防止来自某个连接的老的重复分组在该连接终止后再现,从而被误解为某个新连接的信息,导致错误)
TCP的套接字编程基本函数:
- 服务端和客户端初始化
socket
,得到文件描述符; - 服务端调用
bind
,将绑定在 IP 地址和端口; 调用listen
,进行监听;调用accept
,等待客户端连接; - 客户端调用
connect
,向服务器端的地址和端口发起连接请求; - 服务端
accept
返回用于传输的socket
的文件描述符; - 客户端调用
write
写入数据;服务端调用read
读取数据; - 服务端调用
write
写入数据;客户端调用read
读取数据; - 客户端断开连接时,会调用
close
,那么服务端read
读取数据的时候,就会读取到了EOF
,待处理完数据后,服务端调用close
,表示连接关闭
需要注意的是:客户端 connect 成功返回是在第二次握手,服务端 accept 成功返回是在三次握手成功之后