传输层协议 TCP(一)
○ SYN: 请求建立连接;[CLOSE_WAIT -> LAST_ACK] 进入 CLOSE_WAIT 后说明服务器准备关闭连。[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进。[LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入。[LAST_ACK -> CLOSED] 服务器收到了对 FIN 的 ACK,
·
目录
一、TCP协议
TCP 全称为 "传输控制协议(Transmission Control Protocol"). 人如其名, 要对数据的传
输进行一个详细的控制;
二、TCP 协议段格式
源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去;32 位序号/32 位确认号。4 位 TCP 报头长度: 表示该 TCP 头部有多少个 32 位 bit(有多少个 4 字节); 所TCP 头部最大长度是 15 * 4 = 60
6 位标志位:○ URG: 紧急指针是否有效
○ ACK: 确认号是否有效
○ PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走
○ RST: 对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段
○ SYN: 请求建立连接; 我们把携带 SYN 标识的称为同步报文段
○ FIN: 通知对方, 本端要关闭了, 我们称携带 FIN 标识的为结束报文段
16 位窗口大小: 后面再说
16 位校验和: 发送端填充, CRC 校验. 接收端校验不通过, 则认为数据有问题. 此
处的检验和不光包含 TCP 首部, 也包含 TCP 数据部分.16 位紧急指针: 标识哪部分数据是紧急数据;40 字节头部选项: 暂时忽略;
三、确认应答(ACK)机制
TCP 将每个字节的数据都进行了编号 . 即为序列号 .
每一个 ACK 都带有对应的确认序列号 , 意思是告诉发送者 , 我已经收到了哪些数据 ; 下
一次你从哪里开始发
四、超时重传机制
主机 A 发送数据给 B 之后, 可能因为网络拥堵等原因, 数据无法到达主机 B;如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发;
若 主机 A 未收到 B 发来的确认应答 , 也可能是因为 ACK 丢失了 ;
因此主机 B 会收到很多重复数据 . 那么 TCP 协议需要能够识别出那些包是重复的包 , 并
且把重复的丢弃掉,此时用序列号可以做到去重效果。
超时时间确定
- 最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回".
- 但是这个时间的长短, 随着网络环境的不同, 是有差异的.
- 如果超时时间设的太长, 会影响整体的重传效率;
- 如果超时时间设的太短, 有可能会频繁发送重复的包;
TCP 为了保证无论在任何环境下都能比较高性能的通信 , 因此会动态计算这个最大超时时间
- Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控制, 每次判定超时重发的超时时间都是 500ms 的整数倍.
- 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.
- 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.
- 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接
五、连接管理机制
在正常情况下 , TCP 要经过三次握手建立连接 , 四次挥手断开连接
服务端状态转化 :
[CLOSED -> LISTEN] 服务器端调用 listen 后进入 LISTEN 状态, 等待客户端连
接;
[LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入
内核等待队列中, 并向客户端发送 SYN 确认报文.
[SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入
ESTABLISHED 状态, 可以进行读写数据了.
[ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用 close), 服务
器会收到结束报文段, 服务器返回确认报文段并进入 CLOSE_WAIT;
[CLOSE_WAIT -> LAST_ACK] 进入 CLOSE_WAIT 后说明服务器准备关闭连
接(需要处理完之前的数据); 当服务器真正调用 close 关闭连接时, 会向客户端发送
FIN, 此时服务器进入 LAST_ACK 状态, 等待最后一个 ACK 到来(这个 ACK 是客户
端确认收到了 FIN)
[LAST_ACK -> CLOSED] 服务器收到了对 FIN 的 ACK, 彻底关闭连接.
客户端状态转化 :
[CLOSED -> SYN_SENT] 客户端调用 connect, 发送同步报文段;
[SYN_SENT -> ESTABLISHED] connect 调用成功, 则进入 ESTABLISHED 状
态, 开始读写数据;
[ESTABLISHED -> FIN_WAIT_1] 客户端主动调用 close 时, 向服务器发送结
束报文段, 同时进入 FIN_WAIT_1;
[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进
入 FIN_WAIT_2, 开始等待服务器的结束报文段;
[FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入
TIME_WAIT, 并发出 LAST_ACK;
[TIME_WAIT -> CLOSED] 客户端要等待一个 2MSL(Max Segment Life, 报文
最大生存时间)的时间, 才会进入 CLOSED 状态
- TCP 协议规定,主动关闭连接的一方要处于 TIME_ WAIT 状态,等待两个MSL(maximum segment lifetime)的时间后才能回到 CLOSED 状态.
- 我们使用 Ctrl-C 终止了 server, 所以 server 是主动关闭连接的一方, 在TIME_WAIT 期间仍然不能再次监听同样的 server 端口
- MSL 在 RFC1122 中规定为两分钟,但是各操作系统的实现不同, 在 Centos7 上默认配置的值是 60s;
- 可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看 msl 的值;
TIME_WAIT 的时间是 2MSL?
MSL 是 TCP 报文的最大生存时间 , 因此 TIME_WAIT 持续存在 2MSL 的话
就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失( 否则服
务器立刻重启 , 可能会收到来自上一个进程的迟到的数据 , 但是这种数据很可能是错
误的 );
同时也是在理论上保证最后一个报文可靠到达( 假设最后一个 ACK 丢失 , 那么
服务器会再重发一个 FIN. 这时虽然客户端的进程不在了 , 但是 TCP 连接还在 , 仍然
可以重发 LAST_ACK);
对于服务器上出现大量的 CLOSE_WAIT 状态 , 原因就是服务器没有正确的关闭
socket, 导致四次挥手没有正确完成 . 这是一个 BUG. 只需要加上对应的 close 即可解
决问题。
感谢大家观看!祝大家天天开心、心想事成😊
更多推荐


所有评论(0)