TCP应用层协议(4)

流量控制

接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应.

因此 TCP 支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control);

• 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过 ACK 端通知发送端;

• 窗口大小字段越大, 说明网络的吞吐量越高;

• 接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;

• 发送端接受到这个窗口之后, 就会减慢自己的发送速度;

• 如果接收端缓冲区满了, 就会将窗口置为 0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端.

在这里插入图片描述

接收端如何把窗口大小告诉发送端呢? 回忆我们的 TCP 首部中, 有一个 16 位窗口字段, 就是存放了窗口大小信息;

那么问题来了, 16 位数字最大表示 65535, 那么 TCP 窗口最大就是 65535 字节么?

实际上, TCP 首部 40 字节选项中还包含了一个窗口扩大因子 M, 实际窗口大小是 窗口字段的值左移 M 位;

拥塞控制

在这里插入图片描述

如果是大面积丢包
在这里插入图片描述

这时候如果我们是多个客户端多个服务端呢

在这里插入图片描述

滑动窗口是拥塞窗口和对方窗口的最小值,谁小谁是主要矛盾,即考虑了网络拥堵问题和对方的接受能力,什么是拥塞窗口,拥塞窗口就是一个临界值,网络不会拥塞,这是衡量是否拥塞的标准

虽然 TCP 有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题.

因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据, 是很有可能引起雪上加霜的.

TCP 引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据;

• 此处引入一个概念称为拥塞窗口

• 发送开始的时候, 定义拥塞窗口大小为 1;

• 每次收到一个 ACK 应答, 拥塞窗口加 1;

• 每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口;

像上面这样的拥塞窗口增长速度, 是指数级别的. “慢启动” 只是指初使时慢, 但是增长速度非常快.

• 为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍.

• 此处引入一个叫做慢启动的阈值

• 当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长
在这里插入图片描述

• 当 TCP 开始启动的时候, 慢启动阈值等于窗口最大值;

• 在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回 1;少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就认为网络拥塞;当 TCP 通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降;拥塞控制, 归根结底是 TCP 协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案.

TCP 拥塞控制这样的过程, 就好像 热恋的感觉

延迟应答

如果接收数据的主机立刻返回 ACK 应答, 这时候返回的窗口可能比较小

• 假设接收端缓冲区为 1M. 一次收到了 500K 的数据; 如果立刻应答, 返回的窗口就是 500K;

• 但实际上可能处理端处理的速度很快, 10ms 之内就把 500K 数据从缓冲区消费掉了;

• 在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;

• 如果接收端稍微等一会再应答, 比如等待 200ms 再应答, 那么这个时候返回的窗口大小就是 1M;

一定要记得, 窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;

那么所有的包都可以延迟应答么? 肯定也不是;

• 数量限制: 每隔 N 个包就应答一次;

• 时间限制: 超过最大延迟时间就应答一次;

具体的数量和超时时间, 依操作系统不同也有差异; 一般 N 取 2, 超时时间取 200ms;

在这里插入图片描述

捎带应答

在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 “一发一收” 的. 意味着客户端给服务器说了 “How are you”, 服务器也会给客户端回一个 “Fine,thank you”;那么这个时候 ACK 就可以搭顺风车, 和服务器回应的 “Fine, thank you” 一起回给客户端

面向字节流

创建一个 TCP 的 socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;

• 调用 write 时, 数据会先写入发送缓冲区中;

• 如果发送的字节数太长, 会被拆分成多个 TCP 的数据包发出;

• 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;

• 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;

• 然后应用程序可以调用 read 从接收缓冲区拿数据;

• 另一方面, TCP 的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可以写数据. 这个概念叫做 全双工

由于缓冲区的存在, TCP 程序的读和写不需要一一匹配, 例如:

• 写 100 个字节数据时, 可以调用一次 write 写 100 个字节, 也可以调用 100 次write, 每次写一个字节;

• 读 100 个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100 个字节, 也可以一次 read 一个字节, 重复 100 次;

粘包问题

• 首先要明确, 粘包问题中的 “包” , 是指的应用层的数据包.

• 在 TCP 的协议头中, 没有如同 UDP 一样的 “报文长度” 这样的字段, 但是有一个序号这样的字段.

• 站在传输层的角度, TCP 是一个一个报文过来的. 按照序号排好序放在缓冲区中.

• 站在应用层的角度, 看到的只是一串连续的字节数据.

• 那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是一个完整的应用层数据包. 那么如何避免粘包问题呢? 归根结底就是一句话, 明确两个包之间的边界.

• 对于定长的包, 保证每次都按固定大小读取即可; 例如上面的 Request 结构, 是固定大小的, 那么就从缓冲区从头开始按 sizeof(Request)依次读取即可;

• 对于变长的包, 可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置;

• 对于变长的包, 还可以在包和包之间使用明确的分隔符(应用层协议, 是程序猿自己来定的, 只要保证分隔符不和正文冲突即可);

思考: 对于 UDP 协议来说, 是否也存在 “粘包问题” 呢?

• 对于 UDP, 如果还没有上层交付数据, UDP 的报文长度仍然在. 同时, UDP 是一个一个把数据交付给应用层. 就有很明确的数据边界.

• 站在应用层的站在应用层的角度, 使用 UDP 的时候, 要么收到完整的 UDP 报文, 要么不收. 不会出现"半个"的情况.

TCP 异常情况

进程终止: 进程终止会释放文件描述符, 仍然可以发送 FIN. 和正常关闭没有什么区别.

机器重启: 和进程终止的情况相同.

机器掉电/网线断开: 接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行 reset. 即使没有写入操作, TCP 自己也内置了一个保活定时器, 会定期询问对方是否还在. 如果对方不在, 也会把连接释放.

另外, 应用层的某些协议, 也有一些这样的检测机制. 例如 HTTP 长连接中, 也会定期检测对方的状态. 例如 QQ, 在 QQ 断线之后, 也会定期尝试重新连接

TCP 小结

为什么 TCP 这么复杂? 因为要保证可靠性, 同时又尽可能的提高性能.

可靠性:

• 校验和

• 序列号(按序到达)

• 确认应答

• 超时重发

• 连接管理

• 流量控制

• 拥塞控制

提高性能:

• 滑动窗口

• 快速重传

• 延迟应答

• 捎带应答

其他:

为什么 TCP 这么复杂? 因为要保证可靠性, 同时又尽可能的提高性能.

可靠性:

• 校验和

• 序列号(按序到达)

• 确认应答

• 超时重发

• 连接管理

• 流量控制

• 拥塞控制

提高性能:

• 滑动窗口

• 快速重传

• 延迟应答

• 捎带应答

其他:

• 定时器(超时重传定时器, 保活定时器, TIME_WAIT 定时器等)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93432.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93432.shtml
英文地址,请注明出处:http://en.pswp.cn/web/93432.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双向SSL认证之Apache实战配置

防御未授权访问,为企业级应用构筑双重身份验证防线 本文是关于Apache配置双向SSL认证的深度技术指南,包含全流程操作、调试技巧及企业级解决方案,适用于运维工程师和安全管理员。 1.为什么需要双向认证 ? 核心价值 &#x1f51…

JavaScript 实用工具方法小全

1. 精确获取小数位数/*** 获取数字的小数位数(支持科学计数法)* param {number|string} num - 要检查的数字,可以是数字或字符串形式* returns {number} 返回小数部分的位数* * 实现原理:* 1. 处理科学计数法(如1.23e-…

【易错题】C语言

今日遇到的易错题 #include <stdio.h> int i;//全局变量默认初始化是0 int main() {i--;//-1if (i > sizeof(i)){printf(">\n");}else{printf("<\n");}return 0; }易错点&#xff1a;sizeof的返回值类型实际为无符号整形&#xff0c;因此编…

第七十五章:AI的“思维操控师”:Prompt变动对潜在空间(Latent Space)的影响可视化——看懂AI的“微言大义”!

Prompt变动对潜在空间影响前言&#xff1a;AI的“思维操控师”——Prompt变动对潜在空间的影响可视化&#xff01;第一章&#xff1a;痛点直击——Prompt“难伺候”&#xff1f;改一个字就“面目全非”&#xff01;第二章&#xff1a;AI的“思维圣地”&#xff1a;潜在空间&…

【计算机视觉与深度学习实战】03基于Canny、Sobel和Laplacian算子的边缘检测系统设计与实现

第一章 引言 边缘检测作为计算机视觉和图像处理领域的核心技术之一,在现代数字图像分析中占据着举足轻重的地位。边缘是图像中亮度变化剧烈的区域,通常对应着物体的轮廓、表面方向的不连续性、材质变化或照明条件的改变。准确而高效的边缘检测不仅是图像分割、特征提取、模式…

【大语言模型 02】多头注意力深度剖析:为什么需要多个头

多头注意力深度剖析&#xff1a;为什么需要多个头 - 解密Transformer的核心升级 关键词&#xff1a;多头注意力、Multi-Head Attention、注意力头、并行计算、特征学习、Transformer架构、深度学习 摘要&#xff1a;在掌握了Self-Attention基础后&#xff0c;本文深入探讨多头注…

Python Condition对象wait方法使用与修复

在 Python 中&#xff0c;Condition 对象用于线程同步&#xff0c;其 wait() 方法用于释放锁并阻塞线程&#xff0c;直到被其他线程唤醒。使用不当可能导致死锁、虚假唤醒或逻辑错误。以下是常见问题及修复方案&#xff1a;常见问题与修复方案1. 未检查条件&#xff08;虚假唤醒…

嵌入式硬件——ARM

一、ARM体系结构程序编译的过程&#xff1a;预处理&#xff08;.c-.i&#xff09;&#xff1a;宏替换&#xff0c;头文件展开&#xff0c;去掉注释&#xff0c;特殊符号的处理编译&#xff08;.i-.s&#xff09;&#xff1a;C语言转换成汇编语言汇编&#xff08;.s-.o&#xff…

Flutter 以模块化方案 适配 HarmonyOS 的实现方法

Flutter 以模块化方案 适配 HarmonyOS 的实现方法 Flutter的SDK&#xff1a; https://gitcode.com/openharmony-tpc/flutter_flutter 分支Tag&#xff1a;3.27.5-ohos-0.1.0-beta DevecoStudio&#xff1a;DevEco Studio 5.1.1 Release HarmonyOS版本&#xff1a;API18 本文使…

Redis入门与背景详解:构建高并发、高可用系统的关键基石

本文前言认识Redis单机架构浅谈分布式系统分布式是什么数据库分离和负载均衡引入缓存数据库分库分表引入微服务念补充小结Redis特性介绍持久化支持集群高可用快Redis的应用场景总结前言 在当今这个数据驱动的时代&#xff0c;应用的性能和可扩展性已成为衡量其成功的关键指标。…

Mysql常见的优化方法

数据库优化(底层基础优化) 数据库层面的优化是性能“基础"&#xff0c; 主要包含架构设计、存储引擎、表结构、索引策略、配置参数等方面考虑。目标是减少资源(CPU、IO和内存)消耗。 架构设计 读写分离&#xff1a;将"读操作"和"写操作"分离到不同的数…

利用Claude Code打造多语言网站内容翻译工具:出海应用开发全流程实战教程

一、工具选型与准备Claude Code 简介 Claude Code 是 Anthropic 公司推出的 AI 编程助手&#xff0c;可以辅助开发者生成代码、优化代码结构、进行代码解释等&#xff0c;支持多种主流编程语言。开发环境准备 Claude Code 账号或 API 接入权限Node.js 或 Python 环境&#xff0…

集成运算放大器(反向比例,同相比例)

基础知识&#xff1a;反相比例运算原理&#xff1a;示波器显示&#xff1a;结论&#xff1a;放大倍数为-R2/R1。R3的大小约等于R1与R2的并联电阻。由于放大器的最大输出电压取决于供电电压&#xff0c;所以如果R2为7k时&#xff0c;会导致失真。同向比例原理&#xff1a;示波器…

【HBase】HBaseJMX 接口监控信息实现钉钉告警

目录 一、JMX 简介 二、JMX监控信息钉钉告警实现 一、JMX 简介 官网&#xff1a;Apache HBase ™ Reference Guide JMX &#xff08;Java管理扩展&#xff09;提供了内置的工具&#xff0c;使您能够监视和管理Java VM。要启用远程系统的监视和管理&#xff0c;需要在启动Java…

SQL 语言规范与基础操作指南

SQL 语言规范与基础操作指南 SQL 作为数据库操作的核心语言&#xff0c;遵循规范的语法和书写习惯不仅能提高代码可读性&#xff0c;还能减少错误。本文整理了 SQL 的基础规则、书写规范及常用操作&#xff0c;适合初学者快速上手。 一、SQL 基本规则 1. 书写格式 SQL 语句可写…

产业园IBMS智能化集成系统功能有哪些?

产业园 IBMS&#xff08;建筑集成管理系统&#xff09;智能化集成系统是针对产业园 “多业态、多系统、多租户” 特点设计的全局管理平台&#xff0c;通过整合楼宇自控、安防、消防、能源、停车、租户服务等子系统&#xff0c;实现 “集中监控、协同联动、数据驱动、灵活服务”…

线性代数之两个宇宙文明关于距离的对话

矢量的客观性和主观性宇宙中飘过来一个自由矢量&#xff0c;全世界的人都可以看到&#xff0c;大家都在想&#xff0c;怎么描述它呢&#xff0c;总不能指着它说“那个矢量”吧。数学家很聪明&#xff0c;于是建立了一个坐标系&#xff0c;这个矢量投影到坐标系下&#xff0c;就…

Camx-Tuning参数加载流程分析

调用时序图 一、效果参数在开机时加载 CreateTuningDataManager逻辑分析 1.从xxx_module.xml获取sensor名称和效果参数名称&#xff0c; 比如效果参数名称为&#xff1a;xtc_tsp_sc520cs那么效果库的完整名称就是&#xff1a;com.qti.tuned.xtc_tsp_sc520cs.bin 2.优先从/data/…

《P4180 [BJWC2010] 严格次小生成树》

题目描述小 C 最近学了很多最小生成树的算法&#xff0c;Prim 算法、Kruskal 算法、消圈算法等等。正当小 C 洋洋得意之时&#xff0c;小 P 又来泼小 C 冷水了。小 P 说&#xff0c;让小 C 求出一个无向图的次小生成树&#xff0c;而且这个次小生成树还得是严格次小的&#xff…

Transformer浅说

rag系列文章目录 文章目录rag系列文章目录前言一、简介二、注意力机制三、架构优势四、模型加速总结前言 近两年大模型爆火&#xff0c;大模型的背后是transformer架构&#xff0c;transformer成为家喻户晓的词&#xff0c;人人都知道它&#xff0c;但是想要详细讲清楚&#x…