TCP连接状态转换的几种异常情况

1. TCP连接:

  TCP是基于连接的传输协议,TCP的可靠传输需要建立在一对一的连接的基础之上。
  TCP通过三次握手建立连接,通过四次挥手断开连接。
  三次握手不仅完成连接的建立,同时完成了交换初始序列号(Initial Sequence Number,ISN)。
  通常关闭连接是由应用程序发起(调用close),然而一些服务器(例如Web服务器)在对请求作出响应之后也会发起关闭操作。
  TCP使用一个四元组来唯一的表示一条TCP连接(source_ip、dest_ip、source_port、dest_port)。


2. TCP头部格式:

在这里插入图片描述


3. TCP连接的11种状态转换:

在这里插入图片描述


4. TCP三次握手过程中的状态转换:

第一种情况:正常打开
第二种情况:同时打开
第三种情况:连接建立超时 或 RST复位

4.1 第一种情况:正常打开:

握手过程:
在这里插入图片描述

对应的TCP状态转换:
在这里插入图片描述


4.2 第二种情况:同时打开:

说明:
关键点:
  在 SYN_SENT 状态下收到 SYN报文段,而不是 SYN+ACK 报文段
“同时打开”与“正常连接”过程的区别在于:
  ① 正常过程中,主动打开一方发送SYN后进入SYN_SENT状态,此时等待被动打开一方回复SYN+ACK,主动打开一方在收到回复后转入ESTABLISHED:

SYN_SENT  --(SYN+ACK)-->  ESTABLISHED

  ② “同时打开”过程中,主动打开一方发送SYN后进入SYN_SENT状态,在SYN_SENT状态下并未等来被动打开一方的SYN+ACK,而是只有一个单独的SYN,由此判断对方也调用了主动打开,主动打开一方此时进入SYN_RCVD状态(相当于在LISTEN状态下收到SYN):

SYN_SENT  --(SYN)-->  SYN_RCVD

TIPS:
  “同时打开”是一种非常特殊的场景,正常环境下,服务器是不会主动向客户端发起连接的。
  “同时打开”是TCP协议栈支持的情况,如果应用程序要支持“同时打开”,则必须在代码中既调用connect(发起SYN),又调用accept(连接建立后创建关联连接的fd),既是一个“客户端”,也是一个“服务器”。

握手过程:
在这里插入图片描述

对应的TCP状态转换图:

在这里插入图片描述


4.3 第三种情况:连接建立超时 或 RST复位:

说明:
  主动打开方(客户端)发出的 SYN 报文段石沉大海,无人响应,当SYN达到最大重传次数(net.ipv4.tcp_syn_retries)后,则会连接超时,TCP状态从 SYN_SENT 状态重新传入 CLOSED 状态;
  或者,客户端调用 connect 发起连接后又迅速调用了 close,TCP状态也会重新转入 CLOSED状态。
  (注意:这种情况是SYN报文段根本无人接收,导致客户端收不到任何关于SYN的响应。例如服务器已经关闭。)
  另外一种情况,是服务器收到了客户端的 SYN 报文段,但连接信息有误,例如申请连接的端口号无人监听,此时会回复 RST 复位报文段,用于快速重置连接。

//client:
CLOSED -->  SYN_SENT  --(SYN timeout || close || RST)-->  CLOSED

  同样的,服务端发出的 SYN+ACK 报文段同样有可能会因达到最大重传次数而超时(net.ipv4.tcp_synack_retries),此时服务器状态会由 SYN_RCVD 重新转回 LISTEN 状态。

//server:
CLOSED -->  LISTEN  -->  SYN_RCVD  --(SYN+ACK timeout || close || RST)-->  LISTEN

对应的TCP状态转换图:

在这里插入图片描述


5. TCP四次挥手过程中的状态转换:

第一种情况:正常关闭
第二种情况:同时关闭
第三种情况:四次挥手合并成三次挥手

5.1 第一种情况:正常关闭:

挥手过程:
在这里插入图片描述

对应的TCP状态转换图:
在这里插入图片描述


5.2 第二种情况:同时关闭:

说明:
关键点:
  在 FIN_WAIT_1 状态下收到 FIN报文段,而不是ACK报文段
“同时关闭”与“正常关闭”过程的区别在于:
  ① 在 正常关闭 的过程中,主动发起关闭的一方在发送 FIN报文段后,由 ESTABLISHED 状态进入到 FIN_WAIT_1 状态,并等待对方回复ACK,在收到ACK后随即转入 FIN_WAIT_2 状态:

//client:
ESTABLISHED  --(FIN)-->  FIN_WAIT_1  --(rcv ACK)-->  FIN_WAIT_2

  ② 在 同时关闭 的过程中,主动发起关闭的一方 FIN_WAIT_1 状态下并未收到 ACK报文段,而是收到了对方的FIN,说明对方也主动调用了close关闭连接,此时则由 FIN_WAIT_1 状态转入 CLOSING 状态,并回复ACK:

//client:
ESTABLISHED  --(FIN)-->  FIN_WAIT_1  --(rcv FIN)-->  CLOSING

TIPS:
  在“同时关闭”的过程中引入了一个独有的TCP状态:CLOSING
  在“同时打开”的场景下并未引入新的TCP状态,而是直接复用了 SYN_RCVD(由 SYN_SENT 转入 SYN_RCVD,而非转入ESTABLISHED),这是因为SYN_RCVD有“回复ACK并等待对方回复ACK”的功能,而在连接“正常关闭”的流程中并没有这样的一个状态,因此引入“CLOSING”状态,用于“回复ACK并等待ACK”。
  另外需要注意的是:在“同时关闭”的场景下同样需要 TIME_WAIT 状态。

挥手过程:
在这里插入图片描述

对应的TCP状态转换图:

在这里插入图片描述


5.3 第三种情况:四次挥手合并成三次挥手:

说明:
  四次挥手中的FIN和ACK可能会合并发送,此时主动关闭的一方会直接从 FIN_WAIT_1 状态转入 TIME_WAIT 状态:

FIN_WAIT_1  --(rcv FIN+ACK)-->  TIME_WAIT

注意:
  在服务器端(被动关闭一方),应用程序层面并不会合并发送 FIN + ACK,应用程序需要处理客户端的FIN并首先回复ACK,然后才会检测本端无数据需要发送后才会发送FIN。
但是在内核协议栈层面,可能会有ACK延迟确认,导致ACK等到FIN后合并发送

挥手过程:
在这里插入图片描述

对应的TCP状态转换图:
在这里插入图片描述


6. TCP连接状态下的异常处理:

6.1 TCP处于连接状态下的两种异常:

  1. 应用进程异常退出;
  2. 主机系统异常退出。
  • 对于第一类 应用进程异常退出(例如进程被kill掉 或者 访问空指针等运行异常退出),Linux内核可以检测到进程终止,此时进程占用的系统资源(fd、内存等)都会被回收,同时内核会完成TCP的四次挥手流程(TCP协议栈是在内核实现的),但与进程正常调用close关闭连接不同的是,进程异常退出时系统不会等待TCP发送缓冲区的数据全部发完,而是会直接发送FIN报文段,通知对端关闭TCP连接。
  • 对于第二类情况 主机系统异常退出(例如主机宕机 或者 网线被拔),此时内核一并挂掉,来不及进入TCP四次挥手流程,所以对端是无法感知到发送端的情况的,对端只能等到TCP保活机制超时后断开连接(默认配置下2小时11分钟)。如果主机迅速恢复或者重新插上网线,连接会恢复到异常之前的状态,对端同样无法感知。

6.2 进程异常退出与TIME_WAIT处理:

当TCP连接中的服务端进程异常退出时,Linux内核可以检测到进程崩溃,此时内核会自动进入四次挥手流程关闭与客户端之间的连接。

由于此时服务端扮演的是主动发起四次挥手的角色,所以服务端最后会进入到 TIME_WAIT 状态,此时就引入了一个新的异常边界问题:

当崩溃的 服务器进程 快速完成重启,并尝试绑定LISTEN监听端口时,由于此时端口、fd等资源还在被之前的连接占用(TIME_WAIT状态中),服务器将无法完成bind绑定。

为了让服务器进程可以快速完成服务恢复,对 监控端口的TIME_WAIT状态 的处理方法是:

在socket之后、bind之前,设置套接字选项 SO_REUSEADDR,该选项表示:如果bind要绑定的端口正被占用且处于TIME_WAIT 状态,则可以重用端口。此时即可绑定成功。

SO_REUSEADDR的使用方法:

//listenfd = socket(AF_INET, SOCK_STREAM, 0);

int optval = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

//bind(listenfd, &servaddr);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值