【Linux】传输层协议TCP

【Linux】传输层协议TCP 本文主题内容掌握 TCP 报头格式理解序号、确认应答与超时重传理解三次握手与四次挥手掌握 TCP 状态转换理解滑动窗口与流量控制理解快速重传与拥塞控制理解延迟应答、捎带应答和字节流分析TIME_WAIT与CLOSE_WAIT引言TCP 的复杂性来自传输控制。它不仅要把数据送到对端还要处理丢包、重复、乱序、接收能力和网络拥塞。理解这些机制需要把报头字段、状态机和缓冲区联系起来。一、TCP 基本特点TCP 全称 Transmission Control Protocol主要特点面向连接可靠传输有序字节流全双工提供流量控制提供拥塞控制TCP 的可靠不是绝对保证应用成功处理而是保证在连接有效时把确认过的字节按顺序交付给接收应用无法继续传输时会通过错误或连接关闭通知应用。二、TCP 报头TCP 基本报头为 20 字节带选项时最多 60 字节。2.1 端口号源端口和目的端口用于进程分用。TCP 连接由五元组标识源IP、源端口、目的IP、目的端口、TCP2.2 序号与确认号序号本报文段数据第一个字节在字节流中的编号确认号期望对方下一次发送的字节序号确认号具有累计确认语义。例如 ACK 为 5001表示 5001 之前的字节已经连续收到。2.3 报头长度4 位报头长度以 4 字节为单位。值为 5 表示 20 字节最大值 15 表示 60 字节。2.4 标志位常见标志SYN建立连接同步初始序号ACK确认号有效FIN发送方不再发送数据RST复位连接PSH提示接收端尽快向应用交付URG紧急指针有效2.5 窗口大小接收端通过窗口字段告诉发送端自己当前还能接收多少数据用于流量控制。窗口扩大选项可以突破 16 位字段的直接范围。三、可靠传输3.1 确认应答发送端把已发送但未确认的数据保存在发送缓冲区收到 ACK 后才能释放相应范围。3.2 序号解决的问题序号和确认号可以判断数据是否重复恢复正确顺序表示已经连续收到的范围支撑滑动窗口接收端发现重复数据时会丢弃重复部分但仍可能再次发送 ACK帮助发送端恢复状态。3.3 超时重传发送数据后如果在重传超时时间 RTO 内没有收到有效确认发送端会重传。RTO 不能固定得过小或过大太小正常延迟也会触发无意义重传太大真正丢包后的恢复太慢TCP 根据测量到的往返时间 RTT 及其波动动态估计 RTO并在连续超时时执行退避。TCP 可靠性的基础是序号、确认、超时重传和校验它们共同处理丢失、重复、乱序与损坏。四、三次握手4.1 握手过程客户端发送SYN携带初始序号x服务器发送SYN ACK序号为y确认号为x 1客户端发送ACK确认号为y 1握手完成后双方进入ESTABLISHED。4.2 为什么是三次三次握手使双方确认自己的发送能力正常自己的接收能力正常对方的发送与接收能力正常双方的初始序号已经同步两次不足以让服务器确认客户端已经收到自己的初始序号也更难避免旧连接请求造成状态混乱。4.3 SYN Flood服务器收到 SYN 后会保存半连接状态。攻击者大量发送请求但不完成握手会消耗队列资源。常见缓解方式包括 SYN Cookies、队列调整、速率限制和上游防护。五、四次挥手5.1 关闭过程TCP 是全双工协议两个发送方向需要分别关闭主动关闭方发送FIN被动关闭方发送ACK被动关闭方处理完剩余数据后发送FIN主动关闭方发送ACK中间两个报文在条件允许时可能合并所以抓包中不一定总能看到严格分离的四个报文。5.2 半关闭一方发送 FIN 只表示自己不再发送不妨碍继续接收对方数据。应用可以使用shutdown(fd, SHUT_WR)主动关闭写方向。六、TCP 状态转换6.1 服务端常见状态CLOSED - LISTEN - SYN_RCVD - ESTABLISHED ESTABLISHED - CLOSE_WAIT - LAST_ACK - CLOSED6.2 客户端常见状态CLOSED - SYN_SENT - ESTABLISHED ESTABLISHED - FIN_WAIT_1 - FIN_WAIT_2 - TIME_WAIT - CLOSED6.3 TIME_WAIT主动关闭方在发送最后 ACK 后进入TIME_WAIT通常等待 2MSL。原因包括最后 ACK 丢失时可以重新发送让旧连接中的迟到报文在网络中消失避免影响相同五元组的新连接服务器大量TIME_WAIT不一定是 Bug它说明服务器主动关闭了许多连接。应先确认协议设计和连接复用方式再考虑参数调整。6.4 CLOSE_WAIT收到对端 FIN 后本地进入CLOSE_WAIT。如果长期大量存在通常表示应用已经知道对端关闭却没有及时调用close。注意CLOSE_WAIT通常是应用资源释放问题不能靠缩短 TCP 内核超时从根本上解决。七、滑动窗口与流量控制7.1 滑动窗口如果每发送一段数据都等待 ACK吞吐量会受到 RTT 严重限制。滑动窗口允许发送端在未收到确认前连续发送一定范围的数据。发送缓冲区可以理解为已经确认 | 已发送未确认 | 允许发送 | 暂时不能发送收到累计 ACK 后窗口向右滑动已经确认的数据可以释放新的数据进入可发送范围。7.2 流量控制接收端通过通告窗口rwnd告诉发送端剩余接收空间。发送端不能持续超过接收端处理能力。当窗口为 0 时发送端暂停普通数据并周期性发送窗口探测防止接收端窗口恢复通知丢失后双方永久等待。八、快速重传数据段丢失时后续乱序数据会让接收端重复确认同一个期望序号。发送端连续收到多个重复 ACK 后可以不等超时就重传缺失数据。经典 TCP 通常在收到 3 个重复 ACK 后触发快速重传。现代 TCP 还可以使用 SACK 选择确认更精确地描述已经收到的非连续区间。九、拥塞控制流量控制保护接收端拥塞控制保护网络。实际发送窗口通常受二者共同限制发送窗口 min(rwnd, cwnd)其中cwnd是拥塞窗口。9.1 慢启动连接开始时发送端从较小拥塞窗口起步每个 RTT 快速增加用探测方式寻找可用容量。9.2 拥塞避免达到慢启动阈值后窗口增长变得平缓避免指数增长迅速压垮网络。9.3 丢包后的处理超时通常被视为较严重拥塞窗口明显降低重复 ACK 触发快速重传和快速恢复具体算法可能是 Reno、CUBIC、BBR 等不能把某一张经典曲线当成所有操作系统当前实现的唯一行为但慢启动、拥塞窗口和反馈调节的思想保持一致。十、延迟应答与捎带应答10.1 延迟应答接收端不一定立即为每个小报文单独发送 ACK可能短暂等待看是否有数据可以一起返回看是否能确认更多连续字节给应用读取数据并扩大接收窗口的机会延迟不能无限持续否则会降低交互性能。10.2 捎带应答如果接收端也要发送业务数据可以把 ACK 和响应数据放在同一个 TCP 报文段中减少独立报文数量。十一、面向字节流TCP 为每个连接维护发送缓冲区和接收缓冲区。应用写入的是字节不是独立消息大块数据可能被拆成多个段多次小写可能被合并接收端每次读取的字节数由当前缓冲区和参数决定因此所谓粘包并不是 TCP 报文粘在一起而是应用层没有定义或正确解析消息边界。十二、TCP 异常情况12.1 进程终止进程退出会关闭文件描述符内核通常仍能发起正常 FIN 关闭。12.2 主机崩溃或断网无法发送 FIN 时对端可能要等到重传超时、保活探测或业务心跳超时后才能发现。12.3 RST收到不存在连接的数据、访问未监听端口或连接状态严重不匹配时可能收到 RST。应用读写会表现为连接重置错误。12.4 Keepalive 与业务心跳TCP Keepalive 由内核探测空闲连接默认参数经常较长。业务心跳可以携带应用状态并使用更适合业务的超时二者不能完全互相替代。十三、总结TCP 通过序号、确认、重传和校验实现可靠有序传输通过三次握手建立双方状态通过四次挥手分别关闭两个发送方向。滑动窗口提高吞吐量接收窗口实现流量控制拥塞窗口根据网络反馈调整发送强度。TIME_WAIT保护连接关闭和旧报文隔离CLOSE_WAIT长期堆积通常意味着应用没有关闭连接。TCP 提供字节流不提供业务消息边界应用层仍然必须设计协议并正确处理缓冲区。理解 TCP 的关键是把报头字段看成状态机和缓冲区的控制信息而不是孤立地背诵三次握手与四次挥手。