TCP协议
TCP协议—传输控制协议:对数据的传输进行详细的控制
TCP协议:面向连接,可靠传输,面向字节流
源/目的端口号:表示数据是从那个进程来到哪个进程去
序列号:tcp对每个字节的数据都进行了编号,序列号指的是(这个报文段中第一个字节数据的编号,为了防止丢包和乱序)
确认号:仅当ACK为1时有效,表示期望收到下一个字节的序号
4位TCP报头⻓度: 表⽰该TCP头部有多少个32位bit(有多少个4字节); 所以TCP头部最⼤⻓度是15 * 4 =60
6位标志位:
URG: 紧急指针是否有效
ACK: 确认号是否有效
PSH: 提⽰接收端应⽤程序⽴刻从TCP缓冲区把数据读⾛
RST: 对⽅要求重新建⽴连接; 我们把携带RST标识的称为复位报⽂段
SYN: 请求建⽴连接; 我们把携带SYN标识的称为同步报⽂段
FIN: 通知对⽅, 本端要关闭了, 我们称携带FIN标识的为结束报⽂段
16位窗⼝⼤⼩: 后⾯再说
16位校验和: 发送端产生,接收端校验,包括校验TCP首部及数据部分,保证数据的一致性
16位紧急指针: 标识哪部分数据是紧急数据;
40字节头部选项: 可有可无
面向连接:
建立连接:三次握手
建立连接之前,服务端处于Listen状态,客户端处于Close状态
- 第一次握手:客户端给服务端一个SYN报文,告诉服务端自己想与服务端建立连接,此时客户端处于SYN_SEND状态
- 第二次握手:服务端接收到客户端的SYN请求后,会回应SYN+ACK报文,表示自己接收到了客户端的连接请求,此时服务端处于SYN_REVD状态
- 第三次握手:客户端受到服务端发来的SYN+ACK报文后,发送ACK报文给服务端,表示自己已经收到了服务端的SYN请求,此时客户端处于ESTABLISHED状态,服务端收到ACK后,也处于ESTABLISHED状态,此时已经建立连接了
为什么是三次握手,不是两次或四次握手
- 四次握手没有必要:
在三次握手后,双方已经确认对方既有发送及接收数据的能力 - 两次握手不安全:
1.开始建立连接后,两次握手只能确认一方具有收发数据的功能,但却不能确认另一方是否具有这个能力
2.浪费服务端的资源,而且会导致为一个客户端建立好多连接。
假设没有第三次握手,描述一个这样的场景:客户端发送一个SYN报文请求,因为某些原因滞留了,服务端并没有接收到这个SYN请求,也不会给客户端回应,客户端此时认为报文丢失,就会重新一个SYN报文请求连接,此时服务端接收到了,建立连接。此时已经失效的SYN连接请求发送给了服务端,服务端收到连接请求回复客户端一个SYN+ACK,若是两次握手,此时连接已经建立,服务端等待客户端发送消息,但此时客户端并没有新的连接请求,不会发送消息给服务端,此时服务端就会一直等待浪费服务端资源。三次握手就会避免这个问题,客户端不给服务端恢复最后一次ACK报文,服务端就知道连接不能建立,没有数据传输,就不会再等待接收消息。
三次握手失败了后,服务端要怎么处理?
当服务端没有收到客户端的ACK确认超时等待后,会向客户端发行一个RST报文,然后释放新建的socket资源
终止连接:四次挥手
- 第一次挥手:客户端向服务端发送FIN包,(表示此时已经没有数据要发送了),向服务端请求关闭连接,此时客户端进入FIN_WAIT_1状态。
- 第二次挥手:服务端收到来自客户端的FIN请求包后,向客户端回复一个ACK确认报文,此时服务端进入CLOSE_WAIT状态,这时TCP连接的服务端会向上层应用发送通知,说明客户端已经没有数据要发了,是否还有数据要发给客户端。此时TCO已经处于瓣关闭状态了,因为客户端已经没有数据要发送了。客户端收到ACK报文处于FIN_WAIT_2状态。
- 第三次挥手:当服务端收到上层应用的指令说明没有数据要发送时,会向客户端发送一个FIN包,表明此时我也没有数据发送,可以断开连接了,这时服务端处于LAST_ACK状态
- 第四次挥手:客户端受到FIN包后知道服务端也已经准备好要断开连接,同时自身进入TIME_WAIT状态,向服务端发送一个确认包ACK,告诉服务端可以断开连接了。这个等待状态将等待2MSL,等待后客户端关闭连接,服务端在收到最后一个确认ACK后,断开连接,回收资源
为什么TIME_WAIT状态需要等待2MLS:
MLS:报文最大生命周期
确保最后一个ACK报文可以到达服务端。因为如果服务端没有收到最后一个ACK请求后,就会重新向客户端发送FIN包,客户端也会重新回复一个ACK确认,这样的过程刚好是2MLS
让之前在挥手过程中因为网络延迟滞留的报文失效,使其不会对后面的连接产生影响
多个TIME_WAIT解决: 设置MLS时间
为什么要四次挥手
客户端向服务端通知没有数据要发送后,服务端接收到此消息后只是确保了客户端没有的数据要发送,但此时不能立刻断开连接,因为此时客户端的缓冲区可能还有正在处理的数据,而且服务端还没有确认是否还有数据要发送。