当前位置:首页 > 热点 > 正文

环球微速讯:图解 | 你管这破玩意儿叫 TCP?2022-09-24 15:52:25 | 来源:亚汇网股票行情 | 查看: | 评论:0


(相关资料图)

本文来自微信公众号:你是一台电脑,你的名字叫A经过《这就是物理层、数据链路层、网络层这三层所做的事情。站在第四层的你,就可以不要脸地利用下三层所做的铺垫,随心所欲地发送数据,而不必担心找不到对方了。虽然你此时还什么都没干,但你还是给自己这一层起了个响亮的名字,叫做传输层。你本以为自己所在的第四层万事大吉,啥事没有,但很快问题就接踵而至。问题来了前三层协议只能把数据包从一个主机搬到另外一台主机,但是,到了目的地以后,数据包具体交给哪个程序(进程)呢?所以,你需要把通信的进程区分开来,于是就给每个进程分配一个数字编号,你给它起了一个响亮的名字:端口号。然后你在要发送的数据包上,增加了传输层的头部,源端口号与目标端口号。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=0Win=64240Len=0MSS=1460WS=256B->A[SYN,ACK]Seq=0Ack=1Win=29200Len=0MSS=1424WS=512A->B[ACK]Seq=1Ack=1Win=132352Len=0数据发送阶段A->B[ACK]Seq=1Ack=1Win=132352Len=1424A->B[ACK]Seq=1425Ack=1Win=132352Len=1424A->B[PSH,ACK]Seq=2849Ack=1Win=132352Len=1247B->A[ACK]Seq=1Ack=1425Win=32256Len=0B->A[ACK]Seq=1Ack=2849Win=35328Len=0B->A[ACK]Seq=1Ack=4096Win=37888Len=0B->A[PSH,ACK]Seq=1Ack=4096Win=37888Len=7四次挥手阶段B->A[FIN,ACK]Seq=8Ack=4096Win=37888Len=0A->B[ACK]Seq=4096Ack=9Win=132352Len=0A->B[FIN,ACK]Seq=4096Ack=9Win=132352Len=0(下面少复制了一行ACK,抱歉)后记一提到TCP,可能很多人都想起被三次握手和四次挥手所支配的恐惧。但其实你跟着文中的思路你就会发现,三次握手与四次挥手只占TCP所解决的核心问题中很小的一部分,只是因为它在面试中很适合作为知识点进行考察,所以在很多人的印象中就好像TCP的核心就是握手和挥手似的。本文希望你能从问题出发,真正理解TCP所想要解决的问题,你会发现很多原理就好像生活常识一样顺其自然,并不复杂,希望你有收获~

标签: 窗口大小 流量控制 网络环境

上一篇: 下一篇: