图解 | 你管这破玩意儿叫TCP?
MultiMCU EDU 2022-12-07
劝低并发编程,周一很颓废,周四很硬核
你是一台电脑,你的名字叫 A 经过这篇文章中的一番折腾,只要你知道另一位伙伴 B 的 IP 地址,且你们之间的网络是通的,无论多远,你都可以将一个数据包发送给你的伙伴 B 这就是物理层、数据链路层、网络层这三层所做的事情。 站在第四层的你,就可以不要脸地利用下三层所做的铺垫,随心所欲地发送数据,而不必担心找不到对方了。 虽然你此时还什么都没干,但你还是给自己这一层起了个响亮的名字,叫做传输层 你本以为自己所在的第四层万事大吉,啥事没有,但很快问题就接踵而至。




问题来了




前三层协议只能把数据包从一个主机搬到另外一台主机,但是,到了目的地以后,数据包具体交给哪个程序(进程)呢?

所以,你需要把通信的进程区分开来,于是就给每个进程分配一个数字编号,你给它起了一个响亮的名字:端口号

然后你在要发送的数据包上,增加了传输层的头部,源端口号目标端口号
OK,这样你将原本主机到主机的通信,升级为了进程和进程之间的通信 你没有意识到,你不知不觉实现了 UDP 协议 (当然 UDP 协议中不光有源端口和目标端口,还有数据包长度和校验值,我们暂且略过) 就这样,你用 UDP 协议无忧无虑地同 B 进行着通信,一直没发生什么问题。 但很快,你发现事情变得非常复杂......




丢包问题




由于网络的不可靠,数据包可能在半路丢失,而 A 和 B 却无法察觉。 对于丢包问题,只要解决两个事就好了。 第一个,A 怎么知道包丢了? 答案:让 B 告诉 A 第二个,丢了的包怎么办? 答案:重传 于是你设计了如下方案,A 每发一个包,都必须收到来自 B 的确认(ACK),再发下一个,否则在一定时间内没有收到确认,就重传这个包。 你管它叫停止等待协议。只要按照这个协议来,虽然 A 无法保证 B 一定能收到包,但 A 能够确认 B 是否收到了包,收不到就重试,尽最大努力让这个通信过程变得可靠,于是你们现在的通信过程又有了一个新的特征,可靠交付




效率问题




停止等待虽然能解决问题,但是效率太低了,A 原本可以在发完第一个数据包之后立刻开始发第二个数据包,但由于停止等待协议,A 必须等数据包到达了 B ,且 B 的 ACK 包又回到了 A,才可以继续发第二个数据包,这效率慢得可不是一点两点。 于是你对这个过程进行了改进,采用流水线的方式,不再傻傻地等。




顺序问题




但是网路是复杂的、不可靠的。 有的时候 A 发出去的数据包,分别走了不同的路由到达 B,可能无法保证和发送数据包时一样的顺序。

在流水线中有多个数据包和ACK包在乱序流动,他们之间对应关系就乱掉了。 难道还回到停止等待协议?A 每收到一个包的确认(ACK)再发下一个包,那就根本不存在顺序问题。应该有更好的办法! A 在发送的数据包中增加一个序号(seq),同时 B 要在 ACK 包上增加一个确认号(ack),这样不但解决了停止等待协议的效率问题,也通过这样标序号的方式解决了顺序问题。

而 B 这个确认号意味深长:比如 B 发了一个确认号为 ack = 3,它不仅仅表示 A 发送的序号为 2 的包收到了,还表示 2 之前的数据包都收到了。这种方式叫累计确认累计应答

注意,实际上 ack 的号是收到的最后一个数据包的序号 seq + 1,也就是告诉对方下一个应该发的序号是多少。但图中为了便于理解,ack 就表示收到的那个序号,不必纠结。




流量问题




有的时候,A 发送数据包的速度太快,而 B 的接收能力不够,但 B 却没有告知 A 这个情况。 怎么解决呢? 很简单,B 告诉 A 自己的接收能力,A 根据 B 的接收能力,相应控制自己的发送速率,就好了。 B 怎么告诉 A 呢?B 跟 A 说"我很强"这三个字么?那肯定不行,得有一个严谨的规范。 于是 B 决定,每次发送数据包给 A 时,顺带传过来一个值,叫窗口大小(win),这个值就表示 B 的接收能力。同理,每次 A 给 B 发包时也带上自己的窗口大小,表示 A 的接收能力。 B 告诉了 A 自己的窗口大小值,A 怎么利用它去做 A 这边发包的流量控制呢? 很简单,假如 B 给 A 传过来的窗口大小 win = 5,那 A 根据这个值,把自己要发送的数据分成这么几类。 图片过于清晰,就不再文字解释了。 当 A 不断发送数据包时,已发送的最后一个序号就往右移动,直到碰到了窗口的上边界,此时 A 就无法继续发包,达到了流量控制。 但是当 A 不断发包的同时,A 也会收到来自 B 的确认包,此时整个窗口会往右移动,因此上边界也往右移动,A 就能发更多的数据包了。 以上都是在窗口大小不变的情况下,而 B 在发给 A 的 ACK 包中,每一个都可以重新设置一个新的窗口大小,如果 A 收到了一个新的窗口大小值,A 会随之调整。 如果 A 收到了比原窗口值更大的窗口大小,比如 win = 6,则 A 会直接将窗口上边界向右移动 1 个单位。 如果 A 收到了比原窗口值小的窗口大小,比如 win = 4,则 A 暂时不会改变窗口大小,更不会将窗口上边界向左移动,而是等着 ACK 的到来,不断将左边界向右移动,直到窗口大小值收缩到新大小为止。 OK,终于将流量控制问题解决得差不多了,你看着上面一个个小动图,给这个窗口起了一个更生动的名字,滑动窗口




拥塞问题




但有的时候,不是 B 的接受能力不够,而是网络不太好,造成了网络拥塞 拥塞控制与流量控制有些像,但流量控制是受 B 的接收能力影响,而拥塞控制是受网络环境的影响。 拥塞控制的解决办法依然是通过设置一定的窗口大小,只不过,流量控制的窗口大小是 B 直接告诉 A 的,而拥塞控制的窗口大小按理说就应该是网络环境主动告诉 A。 但网络环境怎么可能主动告诉 A 呢?只能 A 单方面通过试探,不断感知网络环境的好坏,进而确定自己的拥塞窗口的大小。 拥塞窗口大小的计算有很多复杂的算法,就不在本文中展开了,假如拥塞窗口的大小为  cwnd,上一部分流量控制的滑动窗口的大小为 rwnd,那么窗口的右边界受这两个值共同的影响,需要取它俩的最小值。 窗口大小 = min(cwnd, rwnd) 含义很容易理解,当 B 的接受能力比较差时,即使网络非常通畅,A 也需要根据 B 的接收能力限制自己的发送窗口。当网络环境比较差时,即使 B 有很强的接收能力,A 也要根据网络的拥塞情况来限制自己的发送窗口。正所谓受其短板的影响嘛~




连接问题




有的时候,B 主机的相应进程还没有准备好或是挂掉了,A 就开始发送数据包,导致了浪费。 这个问题在于,A 在跟 B 通信之前,没有事先确认 B 是否已经准备好,就开始发了一连串的信息。就好比你和另一个人打电话,你还没有"喂"一下确认对方有没有在听,你就巴拉巴拉说了一堆。 这个问题该怎么解决呢? 地球人都知道,三次握手嘛!

A:我准备好了(SYN)

B:我知道了(ACK),我也准备好了(SYN)

A:我知道了(ACK)

A 与 B 各自在内存中维护着自己的状态变量,三次握手之后,双方的状态都变成了连接已建立(ESTABLISHED)。 虽然就只是发了三次数据包,并且在各自的内存中维护了状态变量,但这么说总觉得太 low,你看这个过程相当于双方建立连接的过程,于是你灵机一动,就叫它面向连接吧。 注意:这个连接是虚拟的,是由 A 和 B 这两个终端共同维护的,在网络中的设备根本就不知道连接这回事儿! 但凡事有始就有终,有了建立连接的过程,就要考虑释放连接的过程,又是地球人都知道,四次挥手嘛!

A:再见,我要关闭了(FIN)

B:我知道了(ACK)

     给 B 一段时间把自己的事情处理完...

B:再见,我要关闭了(FIN)

A:我知道了(ACK)




总结




以上讲述的,就是 TCP 协议的核心思想,上面过程中需要传输的信息,就体现在 TCP 协议的头部,这里放上最常见的 TCP 协议头解读的图。 不知道你现在再看下面这句话,是否能理解: TCP 是 面向连接的、可靠的、基于字节流的 传输层通信协议 面向连接、可靠,这两个词通过上面的讲述很容易理解,那什么叫做基于字节流呢? 很简单,TCP 在建立连接时,需要告诉对方 MSS(最大报文段大小)。 也就是说,如果要发送的数据很大,在 TCP 层是需要按照 MSS 来切割成一个个的 TCP 报文段 的。 切割的时候我才不管你原来的数据表示什么意思,需要在哪里断句啥的,我就把它当成一串毫无意义的字节,在我想要切割的地方咔嚓就来一刀,标上序号,只要接收方再根据这个序号拼成最终想要的完整数据就行了。 在我 TCP 传输这里,我就把它当做一个个的字节,也就是基于字节流的含义了。 最后留给大家一个作业,模拟 A 与 B 建立一个 TCP 连接。

第一题:A 给 B 发送 "aaa" ,然后 B 给 A 回复一个简单的字符串 "success",并将此过程抓包。

第二题:A 给 B 发送 "aaaaaa ... a" 超过最大报文段大小,然后 B 给 A 回复一个简单的字符串 "success",并将此过程抓包

下面是我抓的包(第二题)

三次握手阶段

A -> B [SYN] Seq=0 Win=64240 Len=0

                        MSS=1460 WS=256

B - >A [SYN, ACK] Seq=0 Ack=1 Win=29200 Len=0

                        MSS=1424 WS=512

A -> B [ACK] Seq=1 Ack=1 Win=132352 Len=0

数据发送阶段

A -> B [ACK] Seq=1 Ack=1 Win=132352 Len=1424

A -> B [ACK] Seq=1425 Ack=1 Win=132352 Len=1424

A -> B [PSH, ACK] Seq=2849 Ack=1 Win=132352 Len=1247

B -> A [ACK] Seq=1 Ack=1425 Win=32256 Len=0

B -> A [ACK] Seq=1 Ack=2849 Win=35328 Len=0

B -> A [ACK] Seq=1 Ack=4096 Win=37888 Len=0

B -> A [PSH, ACK] Seq=1 Ack=4096 Win=37888 Len=7

四次挥手阶段

B -> A [FIN, ACK] Seq=8 Ack=4096 Win=37888 Len=0

A -> B [ACK] Seq=4096 Ack=9 Win=132352 Len=0

A -> B [FIN, ACK] Seq=4096 Ack=9 Win=132352 Len=0(下面少复制了一行ACK,抱歉)


一提到 TCP,可能很多人都想起被三次握手和四次挥手所支配的恐惧。但其实你跟着文中的思路你就会发现,三次握手与四次挥手只占 TCP 所解决的核心问题中很小的一部分,只是因为它在面试中很适合作为知识点进行考察,所以在很多人的印象中就好像 TCP 的核心就是握手和挥手似的。
本文希望你能从问题出发,真正理解 TCP 所想要解决的问题,你会发现很多原理就好像生活常识一样顺其自然,并不复杂,希望你有收获~


本文源自微信公众号:MultiMCU EDU,不代表用户或本站观点,如有侵权,请联系nick.zong@aspencore.com 删除!

声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
  • 相关技术文库
  • RF
  • 射频
  • 通信
  • 无线
  • 以太网硬件电路如何在PCB上实现

    我们现今使用的网络接口均为以太网接口,目前大部分处理器都支持以太网口。目前以太网按照速率主要包括10M、10/100M、1000M三种接口,10M应用已经很少,

    8小时前
  • 支持4个双天线DUT的非信令2G/3G/LTE无线综测解决方案

    智能手机和平板电脑的旺盛市场需求迫使生产线寻求更大吞吐量的无线综测解决方案,专攻生产线测试解决方案的Litepoint公司去年6月14日应时而动,推出了同时支持1、4和8部DUT的2G/3G/LTE智能手机和平板电脑无线综测仪IQxstream。 三个月之后,安捷伦生产线测试事业部也宣布推出同时支持4个双天线和8个单天线智能手机或平板电脑DUT的非信令2G/3G/LTE无线综测解决方案(E6607...

    01-11
  • 车载GPS接收机测试

    车载 GPS 导航系统是汽车电子的重要应用,随着汽车进入普通家庭并迅速普及,对车载 GPS 的需求也在急速增长。车载 GPS 导航系统由车载 GPS 接收机和导航软件组成,其中车载 GPS 接收机的性能指标直接影响到导航应用的用户体验,是影响产品性能的关键部分。目前车载 GPS 接收机测试并没有统一的标准,与行业大量应用的手机 GPS 测试相比,需要增加面向汽车应用的测试要求,形成更加全面的符合汽...

    01-11
  • PXA实时频谱分析 应对多制式、高速率通信系统表征和故障诊断

    在航空航天、国防和无线通信等领域中,不断涌现出来的诸多挑战致使系统表征和故障诊断变得更加困难。以雷达和电子战(EW)系统为例,这些系统正变得动态范围更大,运动速度更快,覆盖战场上的更大空间。这种多制式、高速率通信系统的扩展提升了互操作性问题的出现概率。 随着信号变得更加复杂和灵敏,无间隙测量技术——实时频谱分析和时间捕获——逐步获得主流应用的认可。Agilent PXA 信号分析仪更进一步将这些新...

    01-11
  • MIMO波束赋形及其对TD-LTE测试的影响

    1  波束赋形基础知识     “波束赋形”一词有时会被滥用,从而引起混淆。从技术上来说,波束赋形和波束导向一样简单,即两个或更多的天线以受控的延迟或相位偏移来发射信号,从而创造出定向的建设性干涉波瓣(见图1)。 图1 简单波束导向创建的波瓣     TD-LTE系统中所用的波束赋形是一个相对更加复杂的命题,部分原因是终端设备具有移动的特性。一种称为Eigen波束赋形的技术会使用关于RF信道的信...

    01-11
  • 述评SPARQ系列网络分析仪之三:关于S参数(上)

    无源网络如电阻,电感,电容,连接器,电缆,PCB线等在高频下会呈现射频、微波方面的特性。S参数是表征无源网络特性的一种模型,在仿真中即用S 参数来代表无源网络,因此,S参数在射频、微波和信号完整性领域的应用都很广泛。本文将分上、下两篇分别从S参数的定义、S参数的表达方式、S参数的特性、混合模式S参数、S参数测量等多个方面介绍S参数的一些基本知识。 一、S参数的定义 我喜欢找到一句话来概括一个术语。...

    01-11
  • 航空航天和国防应用中的射频干扰信号流化、分析与回放

    理想状态下,接收机将使用砖墙式滤波器,放大器和混频器将永不失真,命令中心始终协调频谱运行,“堵塞”是一个仅会在早餐和举行音乐会时出现的术语。此时,干扰将会出现。 干扰分为有意干扰和无意干扰两类。无意干扰是射频环境的一部分: 手机、无线链路、无绳电话、地面电视、医疗电子设备等都会产生无意干扰。有意干扰是专门创建的信号,目的是破坏目标接收机的运行。我们重点关注有意干扰,最终目标是抵制多余信号。建议的解...

    01-11
  • 运用NI USRP打造出经济实惠的8x8 MIMO测试台

    此技术文章说明了LabVIEW 与USRP 平台的使用方式,进而打造出相位同调(Phase Coherent) 的MIMO 测试台,可以从2x2 扩充为8x8 天线设定,并且用来测试多种MIMO 与多用户的通信研究项目。 1. 8x8 MIMO 简介 现在Single-Link 单连结MIMO (多重输入与多重输出) 通信的概念可说是非常普遍[1],新的无线标准也陆续采用此技术。 比如说LTE A...

    01-11
  • 八天线LTE系统测试挑战

    TD-LTE、FDD-LTE和LTE-Advanced(LTE-A)无线技术使用了几种不同的多种输入多路输出(MIMO)技术。鉴于MIMO系统的复杂性正在日益提高,因此相关的测试方法也将更具挑战性。例如,当前已部署的MIMO技术利用两具天线来改善信道性能。还有一些LTE社区已率先开始采用八天线技术来实现更高的性能。这些先进的技术将使测试方法的选择变得更为至关重要。 要想找到正确的方法,必须要充分理...

    01-11
  • 用于汽车网络开发的局域互联网(LIN)总线详解

    局域互联网(LIN)是一种低成本的嵌入式网络标准,用于连接智能设备。LIN最常见于汽车工业。1.LIN概述    局域互联网(LIN)总线是为汽车网络开发的一种

    01-11
  • 深入洞悉LTE设计与测试

    基于 W-CDMA 的第三代 (3G) 无线系统已在全球广泛部署。W-CDMA 技术通过在下行链路和上行链路模式中提供高速分组接入(HSPA) 技术,始终保持强有力的竞争水平。为确保 3G 系统在未来的竞争力,3GPP 标准 Release 8 首次对 UMTS LTE ( 长期演进 ) 做出了详细规定,它将覆盖未来十年“移动宽带业务”新兴需求的计划。 作为全球测试与测量解决方案的领导者,安捷伦科...

    01-10
  • 浅谈扫频仪在LTE清频测试中的运用

    随着4G在全国各地的不断升温,TD-LTE在全国多个城市已初具规模,越来越多城市将新建LTE基站。对于TD-LTE网络占用的各频段中存在其他网络制式信号占用和外部干扰,应在未建站期间或建网初期展开清频测试,查找和定位干扰来源,净化频段,降低底噪,减轻后续网优工作的难度。LTE扫频仪作为常规路测仪表,比常规频谱仪更适用于清频测试,能以二维频谱图、三维频谱图、采样点信号强度轨迹图等形式展现测量结果,并...

    01-10
下载排行榜
更多
广告