一、TCP简介
1.1 TCP协议特点
(1) 面向连接: 三次握手
(2) 可靠性:(a)三次握手、四次挥手种ACK、SEQ确认 (b)丢包、误码时TCP协议种序号和确认号是保证可靠传输的核心 (c)重传机制 (合理RTT时间内未收到确认)
(3) 面向字节流: 消息边界(无法确定)------>引发粘包问题
(4) 只支持单播 (不支持多播、广播)------->端到端的通信
(5) 全双工通信:客户端send——客户端buffer-- -- -- MSS-- -- --服务端buffer——服务端recv; MSS决定了通信双方最大数据段
buffer内容写入方式一: 写入一条则立即发送一个数据段
buffer内容写入方式二: 写入多条再发送一个数据段(此时数据段size < MSS)
1.2 TCP协议的传输机制
(1) 重传机制: (a)基于时间(超时重传),(b)基于确认信息(快速重传) 解决问题: 丢包、重复传、失序
(2) 流量控制机制: 基于滑动窗口 解决问题:控制对端发送速率、丢失数据可重传
(3) 拥塞控制机制: (a)慢启动(慢开始) (b)拥塞避免 (c)快速重传 (d)快速恢复 解决问题: 网络拥堵,TCP重传导致丢包、延时;TCP继续重传、延时这种恶性循环
(4)可靠传输机制: (a)基于连续 ARQ 协议 (b)基于滑动窗口协议 解决问题: TCP协议可靠性
1.3 TCP协议的包头
序号: 本报文的第一个字节index
确认号: 期望收到next报文发送第一个字节index(潜在表示该确认号之前的字节都是OK的)
数据偏移:整个TCP包头size
6个标志字段:(1)URG标记紧急数据,赋予插队的权利 (2) ACK 确认 (3)通知接收方不用等缓存区填满,先赶紧推送 (4)RST 重新建立连接(5) SYN 同步 (6)FIN 完成
窗口: 接收窗口(告诉对端自己能接收多大数据量)
选项字段: MSS长度、时间戳、窗口扩大多少等
二、TCP三次握手、四次挥手、TCP状态
2.1. 三次握手
客户端 | 服务端 |
CLOSED | CLOSED |
前2次握手期间客户端处于SYN-SENT | Listen(第一次握手期间) |
前2次握手期间客户端处于SYN-SENT | SYN-RCVD(第二、三次握手期间) |
三次握手后Established | 三次握手后Established |
2.2. 四次挥手
服务端 | 客户端 |
FIN-WAIT-1(第一次挥手和第二次挥手期间) | CLOSE-WAIT(第二次挥手和第三次挥手期间) |
FIN-WAIT-2(第二次挥手和第三次挥手期间) | LAST-ACK(第三次挥手后第四次挥手前) |
TIME-WAIT(第三次挥手后) | CLOSED |
2.3. 上图涉及了TCP的10种状态转换(还有一种中间态closing不常见)
客户端:CLOSED SYNC-SENT ESTABLISHED CLOSE-WAIT LAST-ACK CLOSED
服务端:CLOSED LISTEN SYNC-RCVD ESTABLISHED FIN-WAIT1 FIN-WAIT2 TIME-WAIT CLOSED
2.4. TCP三次握手、四次挥手常见面试问题
> 为什么需要三次握手? (防止丢包)
三次握手本质: 保证端到端具备通信能力;
(1)客户端发送SYN ACK给 服务端,服务端收到,确认了客户端的send功能
(2)服务端发送SYN ACK SEQ给客户端,客户端收到,确认了服务端的send、receive功能
(3)客户端再发送ACK SEQ给服务端,服务端收到,确认了客户端的receive功能
如果是2次握手,无法确认客户端是否具有receive功能; 引入下面问题
(a)假定服务端数据ready, 此时服务端给客户端发送数据,客户端会忽略服务端发送过来的数据;(丢包)
(b)假定客户端真不具有receive功能,则也不会给服务端发送消息了
> 为什么需要四次挥手?
四次挥手本质:关闭一个连接(也是两端、且考虑数据未传完的情况)
(1)客户端发送 FIN SEQ给服务端,服务端status:close_wait 客户端status: FIN_WAIT1 不能够send, 但仍能够receive
(2)服务端发送ACK SEQ给客户端,服务端status: close_wait(等待关闭); 原因:服务端数据有可能正在sending,没有发完 客户端status:FIN_WAIT1 ---->FIN_WAIT2
(3) 服务端sended完成发送FIN SEQ给客户端,服务端status: LAST_ACK(等待确认) 客户端status:FIN_WAIT2
(4) 客户端发送ACK SEQ给服务端, 服务端status: LAST_ACK---->CLOSED; 客户端:FIN_WAIT2---->TIME_WAIT
四次挥手确认后,服务端处于CLOSED状态,客户端需要TIME_WAIT等待2MSL才能进入CLOSED; 至此一个连接才算关闭
第一次握手断了客户端的send能力,第二次只是简单应答服务端收到客户端断开请求, 第三次握手断了服务端的send能力,第四次服务端收到请求确认彻底断开;
> 客户端为什么需要等待2MSL才能进入CLOSED状态(防止丢包)
假定第四次挥手的报文丢失,服务端未收到客户端发送ACK、SEQ的话,(最后残留)sending------>sended的数据会由server重新发送给client,client再回ACK、SEQ给server;
这一个来回所需的时间正好是2MSL;