ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

中篇:TCP 为什么可靠又高效?滑动窗口、流量控制、拥塞控制与粘包全解析

中篇:TCP 为什么可靠又高效?滑动窗口、流量控制、拥塞控制与粘包全解析 中篇TCP 为什么可靠又高效滑动窗口、流量控制、拥塞控制与粘包全解析TCP 既要保证可靠性又要尽可能提高性能。本篇围绕 TCP 的核心机制展开滑动窗口、流量控制、拥塞控制、延迟应答、捎带应答、面向字节流与粘包问题。一、滑动窗口一次发送多条数据如果每发一个数据段都要等 ACK性能会较差尤其是往返时间较长时。于是 TCP 引入滑动窗口。窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。例如窗口大小为 4000 字节即四个段。发送前四个段时不需要等待任何 ACK直接发送。收到第一个 ACK 后滑动窗口向后移动继续发送第五个段的数据依次类推。操作系统内核为了维护滑动窗口需要开辟发送缓冲区来记录当前还有哪些数据没有应答。只有确认应答过的数据才能从缓冲区删掉。窗口越大网络的吞吐率就越高。丢包如何处理分两种情况数据包已经抵达ACK 被丢了部分 ACK 丢了并不要紧因为可以通过后续的 ACK 进行确认。数据包直接丢了发送方会触发超时重传如果收到多个重复 ACK也可能触发快速重传。二、流量控制别把接收端撑爆接收端处理数据的速度是有限的。如果发送端发得太快接收端的缓冲区就会满此时再发数据就会丢包。TCP 支持根据接收端的处理能力决定发送端的发送速度这就是流量控制。接收端如何把窗口大小告诉发送端TCP 首部中有一个 16 位窗口字段就是存放窗口大小信息。如果接收端缓冲区满了就会将窗口置为 0。这时发送方不再发送数据但是需要定期发送一个窗口探测数据段使接收端把窗口大小告诉发送端。问题来了16 位数字最大表示 65535那么 TCP 窗口最大就是 65535 字节吗实际上TCP 首部 40 字节选项中还包含了一个窗口扩大因子 M实际窗口大小是窗口字段的值左移 M 位。三、拥塞控制别把网络压垮虽然滑动窗口能高效可靠地发送大量数据但如果刚开始就发送大量数据仍然可能引发问题。因为网络上有很多计算机当前网络状态可能已经比较拥堵。在不清楚网络状态的情况下贸然发送大量数据很可能雪上加霜。TCP 引入慢启动机制先发少量数据探探路摸清当前网络拥堵状态再决定按多大速度传输。核心概念拥塞窗口 cwnd。发送开始时定义拥塞窗口大小为 1。每次收到一个 ACK 应答拥塞窗口加 1。每次发送数据包时将拥塞窗口和接收端主机反馈的窗口大小做比较取较小值作为实际发送窗口。这种增长速度是指数级别的。“慢启动”只是指初始时慢但增长速度非常快。为了不增长那么快引入慢启动阈值 ssthresh当拥塞窗口超过这个阈值时不再按指数方式增长而是按线性方式增长。TCP 开始启动时慢启动阈值等于窗口最大值。每次超时重发时慢启动阈值会变成原来的一半同时拥塞窗口置回 1。少量丢包仅触发超时重传大量丢包就认为网络拥塞。当 TCP 通信开始后网络吞吐量会逐渐上升随着网络发生拥堵吞吐量会立刻下降。拥塞控制归根结底是 TCP 协议想尽可能快地把数据传输给对方但又要避免给网络造成太大压力的折中方案。四、延迟应答与捎带应答延迟应答如果接收数据的主机立刻返回 ACK这时候返回的窗口可能比较小。例如接收端缓冲区为 1M。一次收到了 500K 的数据。如果立刻应答返回的窗口就是 500K。但实际上可能处理端处理速度很快10ms 之内就把 500K 数据从缓冲区消费掉了。如果接收端稍微等一会再应答比如等待 200ms 再应答那么返回的窗口大小就是 1M。窗口越大网络吞吐量越大传输效率越高。目标是在保证网络不拥塞的情况下尽量提高传输效率。但并非所有包都可以延迟应答数量限制每隔 N 个包就应答一次。时间限制超过最大延迟时间就应答一次。一般 N 取 2超时时间取 200ms具体依操作系统不同而有差异。捎带应答在延迟应答的基础上很多情况下客户端和服务器在应用层也是“发一收”的。例如客户端说“How are you”服务器回“Fine, thank you”。这时 ACK 就可以搭顺风车和服务器回应的数据一起回给客户端这就是捎带应答。五、面向字节流与粘包问题创建一个 TCP 的 socket同时在内核中创建一个发送缓冲区和一个接收缓冲区。调用write时数据会先写入发送缓冲区。如果发送的字节数太长会被拆分成多个 TCP 数据包发出。如果发送的字节数太短就会先在缓冲区里等待等到缓冲区长度差不多了或者其他合适时机再发送。接收数据时数据从网卡驱动程序到达内核的接收缓冲区。应用程序调用read从接收缓冲区拿数据。TCP 连接既有发送缓冲区也有接收缓冲区既可以读数据也可以写数据这叫全双工。由于缓冲区的存在TCP 程序的读和写不需要一一匹配。写 100 字节可以一次write也可以 100 次write每次 1 字节。读 100 字节也可以一次read或多次read。粘包问题粘包问题中的“包”是指应用层的数据包。在 TCP 协议头中没有如同 UDP 一样的“报文长度”字段但有序号字段。站在传输层角度TCP 是一个一个报文过来的按序号排好序放在缓冲区中。站在应用层角度看到的只是一串连续的字节数据。应用程序不知道从哪个部分开始到哪个部分是一个完整的应用层数据包。如何避免粘包归根结底一句话明确两个包之间的边界。对于定长的包保证每次都按固定大小读取。对于变长的包可以在包头位置约定一个包总长度字段。对于变长的包还可以在包和包之间使用明确的分隔符。思考UDP 是否存在粘包问题对于 UDP如果还没有上层交付数据UDP 的报文长度仍然在。同时UDP 是一个一个把数据交付给应用层有很明确的数据边界。使用 UDP 时要么收到完整的 UDP 报文要么不收不会出现“半个”的情况。六、异常情况与 TCP/UDP 对比异常情况进程终止进程终止会释放文件描述符仍然可以发送 FIN和正常关闭没什么区别。机器重启和进程终止情况相同。机器掉电 / 网线断开接收端认为连接还在。一旦接收端有写入操作发现连接已经不在了就会进行 reset。即使没有写入操作TCP 自己也内置了一个保活定时器会定期询问对方是否还在。如果对方不在也会把连接释放。应用层协议也可能有检测机制如 HTTP 长连接定期检测QQ 断线后定期重连。TCP 与 UDP 对比TCP 用于可靠传输的情况如文件传输、重要状态更新。UDP 用于对高速传输和实时性要求较高的通信领域如早期 QQ、视频传输UDP 还可用于广播。TCP 和 UDP 都是程序员的工具具体怎么用要根据需求场景判定。用 UDP 实现可靠传输经典面试题参考 TCP 的可靠性机制在应用层实现类似逻辑引入序列号保证数据顺序。引入确认应答确保对端收到了数据。引入超时重传如果隔一段时间没有应答就重发数据。还可以加入滑动窗口、流量控制、拥塞控制等思想。中篇小结本篇重点滑动窗口提高吞吐量流量控制保护接收端拥塞控制保护网络延迟应答、捎带应答提高效率面向字节流与粘包明确应用层边界异常情况与 TCP/UDP 对比UDP 实现可靠传输的思路下一篇将下探到网络层、数据链路层和应用层重点讲 IP、NAT、ARP、DNS 等关键协议。
返回列表