问题
-
TCP 是用来解决什么问题?
-
TCP 和 UDP 的十大核心区别?
-
UDP 和 TCP 的应用场景是什么?
-
UDP 头部为什么没有「首部长度」字段?
-
TCP 头部格式是什么?为什么需要 TCP 协议?
-
服务器监听一个端口,TCP "最大连接数"怎么计算?
-
既然 IP 层会分片,为何 TCP 层还需要 MSS?
-
TCP 的粘包 / 拆包机制是什么?
-
说说 TCP 的三次握手?
-
TCP 初始序列号 ISN 怎么取值?
-
为什么每次建立连接 ISN 都要不同?
-
什么是 SYN Flood 攻击?如何避免?
-
为什么需要四次挥手?
-
四次挥手各报文丢失会怎样?
-
除了四次挥手,还有什么方法断开连接?
-
为什么挥手需要 TIME_WAIT?
-
TIME_WAIT 过多了有什么危害?如何优化?
-
TIME_WAIT、CLOSE_WAIT 状态在哪一步?
-
在 TIME_WAIT 状态收到新 SYN 会怎样?
-
已建立连接时客户端突然断电/进程崩溃会怎样?
-
TCP 何时会出现 RST 报文?
-
TCP 如何保证可靠传输?
-
TCP 超时重传解决了什么问题?
-
有了超时重传为什么还需要快速重传?
-
SACK 引入是解决什么问题?
-
TCP 滑动窗口的作用?
-
流量控制和拥塞控制的步骤是什么?
-
讲讲 TCP 半连接队列和全连接队列?
-
没有 listen/accept 能建立 TCP 连接吗?
-
listen 的 backlog 参数含义是什么?accept 在哪一步?
-
socket 通信的具体步骤是什么?服务端如何提速?
-
TCP Keepalive 与 HTTP Keepalive 区别?
-
TCP 和 UDP 可以使用同一个端口吗?
-
如何在 UDP 之上实现可靠传输?
-
报文乱序怎么办?
-
TCP 序列号/确认号如何变化?
-
已建立连接的 TCP 收到新的 SYN 会怎么样?
-
SYN 报文在什么情况下会被丢弃?
-
TCP 协议有什么缺陷?如何优化 TCP?
-
tcptwreuse 为什么默认关闭?
-
ping 的工作原理是什么?
-
在基于 TCP 的 socket 通信中,调用 send() 方法返回成功是否就能保证对方已经收到消息?请说明 TCP 的机制及可能出现的问题。
44.讲一下OSI七层模型?每一层都是干什么的?
45.讲一讲三次握手每一次握手没成功接收会怎样?
46.为什么收到3次ACK就要将窗口缩小一半?
47.服务器出现大量timewait的原因有哪些?
48.在客户端关闭还收到服务端的FIN报文会怎样?
49.服务器出现大量 CLOSE_WAIT 状态的原因有哪些?
50.建立连接后,服务端进程崩溃后会怎样?
51.客户端调用close之后的内部流程是什么?
52.拔掉网线后,原本的tcp连接还存在吗?
53.tcp的timestamp(时间戳)是干什么用的?
54.tcp有几种计时器?
答案
1.TCP 是用来解决什么问题?
TCP是一种基于 不可靠的IP网络之上,构建了一条面向连接的、可靠、有序的字节流传输服务去解决计算机通信问题。
2.TCP 和 UDP 的十大核心区别?
TCP面向连接(三次握手)
TCP
传输可靠(序列号 ACK 重传)->有序、不丢、不重复
传输粒度 字节流(看不到分段、粘包)
流量控制 滑动窗口
拥塞控制 慢启动、拥塞避免、快速恢复 reno->cubic->BBR
首部开销 20字节+40选项(基础选项(结束选项,无操作)、最大报文段大小、窗口扩大因子、sack(选择重传、时间戳)、其他选项)
传输速度 慢(握手,拥塞控制)
组播/广播 不支持
使用场景 HTTP/HTTPS、FTP、数据库、电子邮件、商务支付
稳定性成本 端口占用多、FD 常驻、握手耗 RTT
UDP
无连接:直接发报文
可能丢包、乱序、重复、不保证送达
传输粒度 报文 一次完整包
无流量控制
无拥塞控制
8字节固定,结构简单
传输速度 低延迟、抖动小、需应用自行容错
原生支持单播 / 组播 / 广播
DNS、直播、在线游戏、通话
资源占用低、无状态,服务端易做并发
4. UDP 头部为什么没有「首部长度」字段?
UDP头部固定为8字节,没必要加这个字段。tcp有是因为tcp头部可变(20+40)
这种设计遵循能省则省的原则,避免了不必要的字段与计算。
5. TCP 头部格式是什么?为什么需要 TCP 协议?
源端口号 目的端口号
序列号
确认号
头部长度(4) 预留长度(6,目前全为0,留待未来使用)6个标志位(SYN,ACK,URG,RST,FIN,PSH) 窗口大小(16,流量控制,指示接收方愿意接收的字节数量。)
校验和(16)紧急指针(16,URG=1生效,指示紧急数据在报文段中的结束位置。)
选项长度(0~40)基础选项(结束选项,无操作)、最大报文段大小(MSS)、窗口扩大因子、sack(选择重传、时间戳)、其他选项
之所以需要 TCP,是因为底层网络(IP 层及以下)会丢包、乱序、拥堵,而上层应用(如 HTTP、文件传输)需要可靠数据。TCP 通过头部字段对应的机制(确认重传、有序重组、流量 / 拥塞控制)解决这些问题,让上层不用关心传输细节,专注业务。简单说,TCP 就是用自己的复杂,换来了整个互联网应用的稳定运行。
URG:紧急指针有效。
ACK:确认号有效。一旦连接建立,该位通常始终为1。
PSH:接收方应尽快将数据交付应用层。
RST:重置连接。
SYN:同步序列号,用于建立连接。
FIN:用于断开连接。
7. 服务器监听一个端口,TCP "最大连接数"怎么计算?
理论上几乎无线(2的32次方)实际受操作系统内核资源和参数限制,通常业务场景 10 万~几百万就会到天花板。
TCP 通过 四元组 唯一标识一条连接{ 源 IP, 源端口, 目标 IP, 目标端口 }
服务器只固定了「目标端口」这一项,其余三项由客户端决定,所以不会出现"端口被占完就接不了连接"的情况。
• 单个客户端主机:最多65535-1024 ≈ 64 K连接(受源端口数限制)
• 多个客户端 IP:乘以 IP 数量,上限可达 2³² 级别(理论)
8. 既然 IP 层会分片,为何 TCP 层还需要 MSS?
IP 分片的缺点
额外开销 每个分片都要重新加 IP 头,总字节数变大。
失包放大 任意一个分片丢失,都要 整包 重传。
路由器压力 路由器需要做分片或重组检查,降低转发性能。
安全风险 分片容易被利用进行分片重组攻击(Teardrop、Fragment Overlap )。
复杂性 传输层收到乱序分片还得等待全部到齐才能交给应用。
TCP是主动拆分,提前避免分片 而IP分片是被迫拆分
还存在IP分片的原因是:数据链路的MTU可能会突然变小 这时候IP分片起了双层保护的作用
上层协议可能会不受 MSS 约束
9. TCP 的粘包 / 拆包机制是什么?
TCP只负责"字节流"不保消息边界 接收端读包慢多余的数据会被存到缓冲区
三种"定界"经典解决方案
定长消息 适合固定结构(如 64 B 行情)。接收端循环读取固定大小即可。
分隔符 常见\r\n 0x00 Stream 查找到分隔符即可切包 注意分隔符转义或禁止内容出现分隔符。
"长度字段 + Payload"报文头占 2/4 B,表示后续正文长度。接收端先读头,再按长度读正文。
定长最简单,分隔最灵活,长度最通用。
10. 说说 TCP 的三次握手?
TCP 三次握手的核心目的是 双向同步通信双方的初始序号(ISN)+ 确认连接可达,为后续可靠的字节流传输打下基础,本质是 "我发、你应、你确认" 的三次交互,确保双方都知道 "对方能发也能收"。
第一次(SYN,A进入SYN_SENT状态) 第二次(SYN+ACK,B从LISTEN进入SYN_RECV状态 A进入ESTABLISHED) 第三次(ACK,B进入ESTABLISHED)
前两次握手报文中(SYN标志位始终是1 它是为了连接,之后连接建立成功了就不用了被设置成0)
第二次握手之后一直有ACK,被始终设置成1,它是为了确认收到了对方数据 。
为什么不是两次握手?
1.防止历史连接(延迟的错误syn)直接跟服务器连接了
2.同步序列号
- 服务器不确定客户端是否收到(SYN+ACK)若第二次丢失 后续发送数据收不到,造成资源浪费 "假连接"
为什么不是四次握手?第二次握手可以分为(SYN和ACK)没必要 为了节省RTT所以合并成一次
11. TCP 初始序列号 ISN 怎么取值?
防止旧连接的包被新连接误接收。
防止黑客伪造TCP包(安全)。
用系统时钟驱动算法+随机函数生成的
你打开一个网页,与服务器 www.example.com:80 建立连接。客户端使用的ISN固定为 1000。连接建立后,你下载了一个图片。
你关闭了这个连接。
此时,网络上可能还有一个迟到的、属于刚才那个连接的TCP包(比如图片的一个数据片段),它的序列号范围在 1000~2000 之间。
一秒钟后,你刷新页面,再次与 www.example.com:80 建立连接。巧合的是,四元组一模一样(你的IP和端口,服务器的IP和端口)。客户端ISN又是 1000。
连接建立成功。就在此时,那个迟到的旧数据包到达了服务器。
服务器看到这个包:"源IP、源端口、目标IP、目标端口都对,序列号 1500 也在当前连接的接收窗口内。嗯,这是一个有效的数据包!"
服务器将这个早已过时的、属于上一张图片的数据,当作新连接的数据提交给你的浏览器。结果就是:数据混乱、连接错误、应用崩溃。
如果ISN是随机且随时间递增的,那么新连接的ISN会远大于旧连接的序列号,那个迟到的旧包序列号会远远落在新连接的接收窗口之外,从而被安全地丢弃
第一次握手定下了客户端的seq(以后的任何客户端的seq都基于这个)反之服务器也是这样 ,并且seq根据每一次发送的数据长度、SYN、FIN进行额外加
13. 什么是 SYN Flood 攻击?如何避免?
攻击者发大量虚假 SYN 包,服务器回 SYN+ACK 后却收不到 ACK,半连接队列资源被耗尽,正常连接被拒绝
常见防御手段
调大 netdev_max_backlog(网卡接收数据包的速度大于内核处理速度时,会有队列保存数据包)
SYN Cookies 不立刻分配半连接状态,收到客户端 ACK 时验证序号合法再分配状态
增大半连接队列长度
缩短半连接超时时间
减少 SYN+ACK 重传次数
14. 为什么需要四次挥手?
TCP 四次挥手是 关闭 TCP 连接的标准流程,核心目的是双向确认 "双方都不再发送数据",确保数据传输的完整性,避免因单方面关闭导致数据丢失。
为什么不是三次挥手?
在 三次握手中,SYN/ACK 是 同时打开
但在 断开连接 时,应用层可能在不同时间结束发送和接收:一端先告诉对方"我没数据要发了"(FIN),但仍能接收对方数据
对方再告诉你"我也没数据要发了"(FIN),你才真的完全关闭
因此,关闭连接 必须分成 两个半关闭 过程,各需要一次 FIN+ACK,合计四次报文。
第 1 步:A 发 FIN → 进入FIN_WAIT_1
第 2 步:B 发 ACK → A 进入FIN_WAIT_2,B 进入CLOSE_WAIT
第 3 步:B 发 FIN → B 进入LAST_ACK
第 4 步:A 发 ACK → A 进入TIME_WAIT,B 收到 ACK 后进入CLOSED
A:CLOSED
15. 四次挥手各报文丢失会怎样?
无论哪一条挥手报文丢失,TCP 都会启动对应端的重传定时器,反复发送丢失的 FIN/ACK,最终依靠重传机制和 TIME_WAIT 阶段保证连接关闭(注意:超时重传的定时器时间是动态变化的 而非2MSL)
16. 除了四次挥手,还有什么方法断开连接?
TCP 还可以通过发送 RST 报文进行急迫中断,以立即释放连接资源。
17. 为什么挥手需要 TIME_WAIT?
TIME_WAIT 状态通过保持连接双倍最大报文生存时间(2×MSL),
保证最后一次 ACK 的可靠传输
防止"旧报文"干扰新连接 确保网络中所有与该连接相关的旧报文 彻底过期。
18. TIME_WAIT 过多了有什么危害?如何优化?
TIME_WAIT 过多会导致本地 端口耗尽、内存/CPU 占用升高,影响新连接建立与系统吞吐,可通过 长连接/连接池、内核参数调优、急迫关闭 等方式优化。
20. 在 TIME_WAIT 状态收到新 SYN 会怎样?
TIME_WAIT 状态下,只有四元组完全相同的旧 SYN会被 RST 拒绝;新连接的 SYN 会正常处理,不影响新连接的建立。这一机制既保证了旧连接的 "隔离",又不阻碍新连接的发起。
21. 已建立连接时客户端突然断电/进程崩溃会怎样?
断电: 服务端会超时重复数据直到上限放弃连接,向应用层返回超时错误,并释放资源 tcpkeepalive
进程崩溃:操作系统关闭该进程的所有socket,内核自动发送 FIN 四次挥手断开连接
22.RST 出现时机
新连接到达但目标端口未打开
收到与当前连接不匹配或不合法的报文
应用或内核触发"急迫关闭"
TIME_WAIT 阶段收到相同四元组,拒绝新 SYN
SYN_SENT 等待阶段收到拒绝或非法响应
23. TCP 如何保证可靠传输?
通过三握四挥,智能重传(超时重传 选择重传 快速重传) 滑动窗口、流量控制、 独特的启动机制(慢启动,之后快速增长) 定时器 序列号 TIME_WAIT机制 校检和
24. TCP 超时重传解决了什么问题?
TCP 的超时重传机制通过为每个未被确认的数据段启动定时器,一旦超过 重传超时时间 (RTO) 仍未收到对应的 ACK,就自动重发,解决了网络中分组丢失后"发送端不知道何时重发"的难题。
25. 有了超时重传为什么还需要快速重传?
超时重传需等到 RTO 到期才能重发,延迟较高;快速重传则利用「三个重复 ACK」信号,能在丢包之后更快地触发重发,显著缩短恢复时间、提升 TCP 性能。
26. SACK(选择确认) 引入是解决什么问题?
SACK通过让接收端告诉发送端究竟哪些数据块已收到,从而避免在多段丢包时因累积 ACK 只能确认"最前面一块"而导致的大量冗余重传。
27. TCP 滑动窗口的作用?
TCP 滑动窗口允许发送方在收到确认前连续发送多段数据,并根据接收方缓冲动态调整可发送量,从而实现流水线式传输与流量控制,极大提高带宽利用率
28. 流量控制和拥塞控制的步骤是什么?
流量控制通过接收方窗口 (rwnd) 限制发送方速率以避免接收端缓冲溢出;拥塞控制通过拥塞窗口 (cwnd) 及"慢启动→拥塞避免→快重传→快恢复"四个阶段动态调节发送速率,防范网络拥塞。
29. 讲讲 TCP 半连接队列和全连接队列?
TCP 在三次握手过程中,服务器先把收到 SYN 后尚未完成握手的连接放入半连接队列(SYN queue),待收到客户端 ACK 后再移入全连接队列(Accept queue),由应用层accept()依次取出,以此区分"握手中"和"已就绪"两种状态并保护系统免遭 SYN 洪水攻击。
30. 没有 listen/accept 能建立 TCP 连接吗?
TCP 标准流程中被动打开(listen/accept)是必须的,只有少见的"同时主动打开或使用原始套接字造包,才可在不调用 listen/accept 的情况下完成三次握手。
31. listen 的 backlog 参数含义是什么?accept 在哪一步?
全连接队列:backlog直接定义其上限(受min(backlog,somaxconn)约束)
半连接队列:backlog是重要输入,但最终受f(tcp_max_syn_backlog)等系统参数限制
更准确的说法:backlog是全连接队列的直接控制器,是半连接队列的重要影响因素。
32. socket 通信的具体步骤是什么?服务端如何提速?
服务器:socket bind listen accept recv/send close 客户端:socket bind connect send/recv close
服务端如何提速?
要让服务器在高并发、高吞吐场景中跑得更快,需从 接入层 → I/O 层 → 并发层 → 零拷贝层 → 系统调优 五个方向优化。
优化连接接入
调大 backlog 与系统上限listen(ls, backlog)
Linux 参数net.core.somaxconn、net.ipv4.tcp_max_syn_backlog
开启 SO_REUSEPORT允许多进程/线程在同一端口listen,内核自动 load-balance 到各个 CPU 核。
SYN Cookies在半连接队列溢出时启动,抵御 SYN 洪水。
高效的 I/O 模型
阻塞 I/O + 线程/进程池
select/poll(描述符多了就慢)
epoll(Linux)、kqueue(BSD)、IOCP(Windows)支持事件就绪通知,O(1) 处理海量 socket
异步 I/O / io_uring用户态提交、内核态回调,避免上下文切换
并发架构
线程池 / 进程池预先创建工作线程,复用资源,避免频繁fork/pthread_create。
协程 / 纤程(如 libuv、go、boost::asio)在单线程内做数万并发,切换成本微乎其微。
零拷贝技术
sendfile()直接在内核空间把文件页零拷贝到网络缓冲区。
splice()/vmsplice()在管道/套接字间转移数据,无需用户空间缓冲区。
mmap + writev把文件映射到内存,多段写合并为一次系统调用。
系统参数调优
文件描述符上限:ulimit -n
TCP 时间等待重复利用:net.ipv4.tcp_tw_reuse/tcp_tw_recycle
TCP 快速打开:TCP_FASTOPEN,减少一次 RTT
TCP_NODELAY:关闭 Nagle,降低小包延迟
调整内核网络缓冲区:net.ipv4.tcp_rmem/tcp_wmem
33. TCP Keepalive 与 HTTP Keepalive 区别?
TCP Keepalive 是在 传输层定期发"空心跳包"探测并清理闲置的 TCP 连接;而 HTTP Keep-Alive(持久连接)是 应用层通过 HTTP 头部复用同一个 TCP 连接来发多次请求/响应,减少握手开销。
34. TCP 和 UDP 可以使用同一个端口吗?
在操作系统里,TCP 和 UDP 端口号属于不同的协议命名空间,同一台机器上可以同时在 TCP 层和 UDP 层"占用"同一个端口号,互不冲突。
当报文到来时,内核首先看 协议类型
35. 如何在 UDP 之上实现可靠传输?
在 UDP 之上实现可靠传输,需要自行引入 分段与序号、校验和、确认与重传、超时重传、流量/拥塞控制 等机制,模拟 TCP 的可靠特性。
36. 报文乱序怎么办?
对乱序报文,通过"序列号 + 接收缓存 + 重排序算法"把分片先缓存在本地,一旦缺口被填补就按序交付;在 TCP 中还可借助 SACK 通知发送端只重传缺失区间,保证上层收到的始终是有序数据。
38. 已建立连接的 TCP 收到新的 SYN 会怎么样?
不同四元组 连接建立
相同四元组 不断开连接
相同四元组合理SEQ 发送challengeACK 状态同步或攻击检测
相同四元组 无效SEQ 发送RST或丢弃 明显异常或攻击
39. SYN 报文在什么情况下会被丢弃?
当 TCP 处于非 LISTEN/SYN_SENT 状态、半连接队列已满、报文校验或格式不合法,或因防火墙/ACL 策略拦截时,收到的 SYN 报文会被内核直接丢弃(有时还会回复 RST)。
40. TCP 协议有什么缺陷?如何优化 TCP?
TCP 可靠有序,但因"三次握手/四次挥手"开销大、拥塞控制保守、HOL 阻塞及对高带宽-时延或无线环境不友好,网络迁移需要重新建立等缺陷。
需要通过SACK/Timestamp、Fast Open、新拥塞算法(CUBIC/BBR)、多路径(MPTCP)、零拷贝/硬件卸载等多种手段来优化。
TCP 三次握手的性能提升
调整 SYN 报文重传次数
调整 SYN 半连接队列长度
调整 SYN+ACK 报文重传次数
调整 accept 队列长度
绕过三次握手
TCP 四次挥手的性能提升
调整 FIN 报文重传次数
调整 FIN_WAIT2 状态的时间
调整孤儿连接的上限个数
调整 time_wait 状态的上限个数
复用 time_wait 状态的连接
TCP 数据传输的性能提升
扩大窗口大小
调整发送缓冲区范围
调整接收缓冲区范围
接收缓冲区动态调节
调整内存范围
41. tcptwreuse 为什么默认关闭?
tcp_tw_reuse 是 Linux 内核中优化 TIME-WAIT 状态连接的核心参数,允许复用处于 TIME-WAIT 状态的端口。
核心作用
减少 TIME-WAIT 连接占用的端口资源,缓解高并发场景下的端口耗尽问题。
加速新连接建立,避免因等待 TIME-WAIT 超时(默认 60 秒)导致的连接延迟
默认关闭,是因为复用处于 TIME-WAIT 的 TCP 套接字会破坏 2MSL 等待机制,导致旧报文"串门"到新连接中,危及连接可靠性和安全性。
42. ping 的工作原理是什么?
ping 是基于 ICMP 协议的连通性测试工具,原理:发送方发 ICMP 回声请求包(Type=8),目标主机若可达且允许响应,就回 ICMP 回声应答包(Type=0),通过请求 - 应答判断目标是否通、延迟多少、丢包率如何。它不依赖 TCP/UDP,直接在网络层工作,流程是:构造 ICMP 请求→封装 IP 包→路由到目标→目标回应答→计算 RTT 和丢包率。(RTT:发送请求到收到应答的时间)但要注意,有些服务器会禁用 ICMP,这时 ping 不通但服务可能正常;ping 通也不代表服务没问题,只是主机可达。
43. 在基于 TCP 的 socket 通信中,调用 send() 方法返回成功是否就能保证对方已经收到消息?请说明 TCP 的机制及可能出现的问题
调用 send() 返回成功仅表示数据写入内核缓冲区,需通过 TCP 协议的确认机制(ACK)才能确保对方收到消息。
44握手/挥手丢失的时候重传是指数回避重传 建立连接后丢失才是动态定时器重传
应用层 用户接口 提供网络服务给应用程序
HTTP, FTP, SMTP, DNS Data "做什么"
浏览器显示网页内容
表示层 数据翻译 加密、压缩、格式转换
SSL/TLS, JPEG, MPEG Data "看起来怎样"
把数据解密成能看懂的样子
会话层 对话控制 建立、管理、终止会话
NetBIOS, RPC Data "跟谁说话"
保持登录状态,管理通话
传输层 端到端连接 可靠性、流量控制、错误恢复
TCP, UDP Segment (TCP)/Datagram(UDP) "可靠送达"
确保数据完整到达对方
网络层 寻址和路由 选择最佳路径,IP寻址
IP, ICMP, Router Packet "走哪条路"
GPS导航,找最佳路线
数据链路层 MAC地址寻址 帧同步、错误校验
Ethernet, Switch, Bridge Frame "下一站去哪"
小区内门牌号寻址
物理层 比特流传输 物理介质、电气特性
Hub, Cable, Fiber Bit "物理道路"
修路、车辆本身
47.服务器出现大量 TIME_WAIT 状态的原因有哪些?
http没使用长连接
http长连接超时
http长连接的请求数量达到上限
49.服务器出现大量 CLOSE_WAIT 状态的原因有哪些?
核心诱因是 应用程序未正确处理连接关闭事件,其次是资源耗尽、网络异常或第三方组件问题。解决的关键是:确保应用程序在检测到连接关闭(如 read() 返回 0)或使用完毕后,主动调用 close();同时合理配置 fd 上限、超时参数,避免资源泄漏。
50.建立连接后,服务端进程崩溃后会怎样?
内核自动发送 FIN 包,触发 TCP 四次挥手,清理连接资源;
客户端若正在 I/O:写操作返回 ECONNRESET,读操作返回 0;
客户端若空闲:连接变为 "半开连接",需依赖 TCP Keepalive 检测断开;
客户端必须处理 recv() == 0 和 send() 错误,避免资源泄露或程序崩溃。
51.客户端调用close之后的内部流程是什么?
客户端调用 close,表明客户端没有数据需要发送了,则此时会向服务端发送 FIN 报文,进入 FIN_WAIT_1 状态;
服务端接收到了 FIN 报文,TCP 协议栈会为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,应用程序可以通过 read 调用来感知这个 FIN 包。这个 EOF 会被放在已排队等候的其他已接收的数据之后,这就意味着服务端需要处理这种异常情况,因为 EOF 表示在该连接上再无额外数据到达。此时,服务端进入 CLOSE_WAIT 状态;
接着,当处理完数据后,自然就会读到 EOF,于是也调用 close 关闭它的套接字,这会使得服务端发出一个 FIN 包,之后处于 LAST_ACK 状态;
客户端接收到服务端的 FIN 包,并发送 ACK 确认包给服务端,此时客户端将进入 TIME_WAIT 状态;
服务端收到 ACK 确认包后,就进入了最后的 CLOSE 状态;
客户端经过 2MSL 时间之后,也进入 CLOSE 状态;
52.拔掉网线后,原本的tcp连接还存在吗?
有数据传输:启动超时重传,重传时间里 服务器觉得无事发生 若超过重传次数 就断开
没数据传输:若开启tcpkeepalive 探测 没开启就僵尸连接
53.tcp的timestamp(时间戳)是干什么用的?
1.防止序号回绕(PAWS,Protect Against Wrapped Sequence numbers)
TCP 的序号是 32 位的,当数据传输速率极高时,序号会快速用完并 "回绕"(比如从 4294967295 回到 0)。时间戳会给每个报文打上发送方的时间标记,接收方可以通过时间戳判断 新报文 和 旧报文的回绕重传,避免把旧数据当成新数据接收。
2.计算往返时间(RTT)更精准
传统 RTT 计算是基于报文的 "发送 - 确认" 间隔,但如果出现报文重传,很难区分是第一次报文的确认还是重传报文的确认。时间戳会在报文里携带发送时间,确认报文会带回这个时间戳,接收方可以直接用 "当前时间 - 发送时间" 计算 RTT,不受重传的干扰,结果更准确。
3.另外,它也能辅助TIME_WAIT 复用(判断新连接的时间戳是否比旧连接的更新,避免复用过期连接)
54.tcp有几种计时器?
重传计时器:管 "数据丢了重传",是 TCP 可靠的核心;
TIME_WAIT 计时器:管 "连接关闭后的安全收尾",防残留报文;
坚持计时器:管 "接收方窗口满时的探查",防死锁;
保活计时器:管 "空闲连接的存活检测",清无效连接;
延迟确认计时器:管 "ACK 报文的优化发送",省带宽。
一、核心计时器分类(按功能优先级排序)
- 重传计时器(Retransmission Timer,RTO Timer)
核心作用:TCP 最核心的计时器,负责 "超时重传"------ 发送方发完数据段(比如一个 TCP 报文)后,立刻启动这个计时器。
触发逻辑:若在计时器超时前收到接收方的 ACK(确认应答),则关闭计时器;
若超时未收到 ACK,认为数据丢失,立即重传该数据段,并重设计时器(超时时间会动态调整)。
关键细节:超时时间(RTO)不是固定值,会根据网络延迟(RTT,往返时间)动态计算(比如网络卡顿时,RTO 会自动拉长,避免频繁无效重传)。
- 超时等待计时器(TIME_WAIT Timer)
核心作用:解决 "连接关闭后,网络中残留的延迟报文" 问题 ------ 主动关闭连接的一方(比如客户端)发送 FIN 报文后,不会立即释放连接,而是启动这个计时器。
触发逻辑:计时器持续 2 倍的最大报文段寿命(2MSL,通常是 1-4 分钟),期间保持端口占用,防止新连接收到旧连接的残留报文。
实际意义:避免 "端口复用后,新连接误接收旧连接的延迟数据",是 TCP 连接关闭的 "安全收尾"。
- 坚持计时器(Persist Timer,也叫 "保活计时器" 的细分场景)
核心作用:解决 "接收方缓冲区满了,发送方一直等不到窗口更新(Window Update)" 的死锁问题。
触发逻辑:接收方缓冲区满时,会通知发送方 "窗口为 0"(暂停发送);发送方启动坚持计时器,每隔一段时间(比如 5 秒)发送一个 "窗口探查报文",询问接收方 "缓冲区空了吗?"。
关键细节:避免发送方一直阻塞等待,接收方缓冲区空了后也没机会通知的死锁场景。
- 保活计时器(Keep-Alive Timer)
核心作用:检测 "长时间无数据传输的连接是否还存活"------ 比如客户端和服务器建立连接后,长时间不发数据(比如聊天软件后台挂着)。
触发逻辑:默认空闲时间(比如 2 小时)后,启动计时器,发送 "保活探测报文";若连续几次(通常 3 次)没收到对方响应,认为连接已断开,主动关闭连接。
注意:该计时器默认关闭,需由应用层开启(比如 HTTP 长连接、SSH 连接会启用),避免无效连接占用资源。
- 延迟确认计时器(Delayed ACK Timer)
核心作用:优化 ACK 报文的发送效率,避免 "收到一个小数据段就立即回复 ACK" 导致的网络开销。
触发逻辑:接收方收到数据后,不立即发送 ACK,而是启动延迟计时器(通常 200ms 以内);若在计时器期间,有数据要发给对方(比如回复应用层数据),就把 ACK 附在数据报文中一起发送("捎带 ACK");若超时没数据要发,再单独发送 ACK。
实际意义:减少网络中单独的 ACK 报文数量,降低带宽占用。