经过故事引伸网络协议TCP

讲一个故事。


三次握手

 long time ago,通讯并不发达,两国之间的贸易却络绎不绝。但码头始终有限,若是贸然的把货物运过去,若是这时候有别的商家已经占领了码头。这样不得不排队了。后来,他们训练了一种海鸟,运送以前,先用海鸟报个信: 算法

  1. 五弟,我要发一些货过去。
  2. 收到,老地方,不见不散。

 一开始这个方式挺好用的,直到有一年夏天,五弟找上门来了:我等了你一天,你的货呢?我交了钱借用了一天的码头,都白交了。二哥:我也着急呀,你一直没回信,我都等了两天,我不知道咋肥四,就没发了。应该是回信的那只鸟,被大风刮走了。最近海上天气很差,想必我放的那只鸟也是历经千辛万苦才去到你那。这样吧,五弟,我改一下流程吧:缓存

  1. 五弟,我要发一些货过去。
  2. 收到,老地方,不见不散。
  3. 五弟,好的,老地方。

五弟琢磨了一下,前面的鸟可以一来一回,二哥能看出海上没有危险。我收到二哥的消息后也能看出海上无风雨,这时我再去借码头,也能节省一些时间,妙,实在妙,仍是二哥聪明,只是二哥要比我多训练一倍的鸟。五弟哪里的话,浪费这点资源算什么呢。服务器

三次握手就这样诞生了。网络

流量控制

过了一些时日,五弟又来找二哥商量了:码头上的仓库空间,人力始终有限,二哥一次派了这么多艘船来,五弟实在忙不过来,船都堵在渡口,人家的船进不来,出不去啊。为了此事二哥想了一宿,找来了五弟商量:五弟呀,这个确实是个头疼的问题呀。并发

最简单的办法就是一开始你就告诉我你能处理多少货,我就派一批船过去。等你处理完了通知我,我再派一批过去。可是这种方式应变能力过低了,假设港口一开始没这么堵,可是可能还有一些商家在海上来往,结果我这一批派过去,就致使堵塞拥挤了。这个应变能力能理太差了,要提升这个应变能力,就不能派太多的船涌进港口,只能一小批,一小批的派了。指针

这样你每次收到货以后,就让回来的船告诉我你那里剩余多少空间,我好安排下一趟船只。五弟挠挠头,不明白。二哥敲了下这木鱼脑壳道:假设咱们要运送720的货,你码头的仓库最多能存360的货物,我每次派100的货物,固然个人每艘船只能载重是10(MTU 最大传输单元限制)。cdn

  • 第一趟,我送过去100,我须要派10艘过去,你让返回的船老大告诉我你那里还剩260的空间。
  • 第二趟,我送过去100,我须要派10艘过去,你让返回的船老大告诉我你那里还剩160的空间。
  • 第三趟,我送过去100,我须要派10艘过去,你让返回的船老大告诉我你那里还剩60的空间。
  • 第四趟,我送过去60,我须要派6艘过去,这时候仓库已满,你开始让工人搬运,等你搬运好了,就通知我。
  • 第五趟,收到五弟那边的通知,我开始送过去100,我须要派10艘过去,你让返回的船老大告诉我你那里还剩260的空间。
  • 第六趟,我送过去100,我须要派10艘过去,你让返回的船老大告诉我你那里还剩160的空间。
  • 第七趟,我送过去100,我须要派10艘过去,你让返回的船老大告诉我你那里还剩60的空间。
  • 第八趟,我送过去60,我须要派6艘过去,这时候货就发完了,圆满大吉。

借助窗口解决了流量控制的问题。中间件

丢包重传

没过多久,五弟又来找二哥商量了:我收到的货物缺斤少两的,对不上数呀,我猜呀,海上风云莫测,可能有些船只失踪了,这可咋办呀。二哥想了想,能咋办,重发呗。这样,我给每个船只编上号,到了一段时间,没回来的船只,我再重发那批货物吧。至于间隔多久才决定重发,这个很是重要。
  • 设长了,重发慢了,丢了老半天才发过去,效率过低了,也让五弟等过久了。
  • 设短了,更恐怖,可能会致使没有丢的也重发,这样就重发多了,更多的船堵在海上,许久不能到达返回,致使更多的超时,更多的重发。

再加上海上风云莫测,每次来回的时间不是固定的。只能动态的估算这个值了。这样,每批次的船只一来一回算一个单位(RTT)。而后根据这个RTT的时间计算超时时间(RTO)当发生了重发,就会将超时时间加倍。防止太频繁重传致使更加拥挤。blog

重传歧异

可是这样的会有一个问题,假设7号船一直没回来,这时候再派一个7号船过去,许久后,终于回来了,那么这艘船是第一艘的仍是重发的那艘呢?忽略说能认出船老大的陈独秀同窗(抠鼻)。队列

  • 若是回来的船的是重发的那艘,假设是按第一艘来算,那么间隔时间算长了。
  • 若是回来的船的是第一艘的,却又按照重发的那艘来算,间隔时间又算短了。

这是一个苦差事,具体怎么算,仍是请位大师来算吧。此事算了了。

慢启动

五弟又过了找二哥了:运720的货都跑了8趟了,那送7200的货那还不得九九八十一趟啊。这效率不行啊,二哥道:你想到的我也想到了,一开始我并不知道海上的拥挤状况,因此不敢派太多的船,我想了一个办法,先发的慢一点,探测一下状况,而后再慢慢提速。假设我一开始派n艘船。

  • 先假定cwnd = 1,表示我这个批次派 cwnd*n 艘船。
  • 每当有一艘船回来,cwnd++,线性上升。
  • 每当过一个RTT,也就是当前批次的船回来了,cwnd = cwnd *2,指数上升。

这样,就能够解决效率低的问题了。

拥塞避免

固然,不可能一直是增长。这样拥堵只是时间问题。因此须要一个阈值。

  • 当 cwnd < 阈值,使用慢启动算法
  • 当cwnd >= 阈值,使用拥塞避免算法

拥塞避免算法的思路就是下降加速度,让它缓慢的增加。

  • 每当有一艘船回来,cwnd = 1/cwnd
  • 每当过一个RTT,cwnd++

拥塞处理

以上都是正常的状况,当发生了重传,说明发生了拥挤,就不能再发这么多船了,这时候cwnd减半,从新进入慢启动。

好了,故事就讲到这里了。

当出现了RTO超时重传,由于ack都收不到了,因此它的处理会比较猛烈:

  • 将门限ssthresh的值设为当前cwnd值的一半,也就是阈值。之因此减半,是为了公平性,腾出空间给其余新连接保证带宽。
  • cwnd设为1。
  • 从新进入慢启动。

cwnd决定了发送窗口的大小,若是只是出现了轻度的拥堵,就直接猛烈缩小窗口,进入慢启动后,cwnd恢复的很慢,这显然得不偿失,因此须要一种主动触发重传的机制,就有了后来的快速重传和快速恢复。

快速重传

仅仅只是靠超时重传,并不能发生了包丢失,却要等到超时才开始重传,这显然效率不够,因此须要找到重传的规律。虽然咱们发的包是有序的,可是IP包是无序的,因此会致使到达的包出现无序的状况。先来看下下面一组数据。

  • 1,2,3,4        已发送,已确认到达
  • 5,6,7,8,     已发送,未确到达
  • 9,10,11 ,12    在发送缓冲区等待发送,滑动窗口已经没有空间了。

要保证可靠性,就必需要保证顺序和完整,来看看事故发生现场。

  • 5,6,7,8。ack=9 , 由于Seq=5,length = 4,ack = seq+lenght,window size 剩余 4。不会每个都返回ack,这样将会消耗大量的带宽。
  • 6,5,7,8。ack=5,ack=5,ack=9,6到达的时候,发现顺序不对,则会发出ack=5,期待客户端下次发送seq=5的包,由于尚未达到三次因此客户端不会理会这个信息,果真后面就如期而至。
  •  6,7,8,5。ack=5,ack=5,ack=5,ack=5,ack=9。重复三次了,因此后面重发了5。

从上面的状况能够看出不论是乱序仍是丢包,都会收到重复的ack的。在快速重传算法中,当收到三次重复的ack,就认定它是丢包了。但实际上,三次重复ack并不能判断出是丢包或乱序,只能说出现了问题,它只是在效率和过早重传之间的一个权衡。

  • 若是两次重复ack就发送可能会由于频繁发送致使拥挤堵塞。
  • 若是太晚发送效率就跟不上。
  • 若是三次接收端都能收到重复ack,说明网络不会太差。

收到了三次重复的ack,进入快速重传须要作几件事情:

  • ssthresh =cwnd/2
  • cwnd=ssthresh
  • 这时候由于cwnd等于阈值,因此从新进入拥塞避免阶段

因为快速重传有多是由于顺序的问题而误判,或者只是轻微的拥堵,致使进入了拥塞避免阶段,这时候为了达到快速恢的目的,将会中止发送后面的数据,只发送重传数据,为了提升恢复效率,将会使用快速恢算法。

快速恢复

为了保证快速重传效率,进入快速恢复阶段会有如下几个步骤。

  • 因为在上一个阶段,cwnd和ssthresh变成了,ssthresh =cwnd/2,cwnd=ssthresh+3,之因此加3,是由于刚刚收到了3个重复的ack。
  • 当再次收到重复的ack,cwnd = cwnd+1。
  • 当收到新的ack,非重复的ack,cwnd=ssthresh,退出快速恢复阶段,进入拥塞避免状态。

总的来讲就是腾出空间,马不停蹄。

TCP 重传机制

在上面的重传原理介绍中,咱们还忽视了一个问题,例如客户端在发送1,2,3,4,5,6,7包时,2,4,6,包丢了,这种状况仍是比较常见的,这时候就会面临一个问题,究竟是一个一个重传,仍是将2后面的包都重发过去。

  • 停等协议。这时候接收方和发送方的窗口大小都是1,这样每次只能发送一个,也就是一个一个重传。缺点是效率过低。
  • 后退n帧协议。使用这个协议,为了保证接收方有足够的空间,2以后的数据都要丢弃,而后发送方将2后面的数据都所有发送。缺点是须要有足够大的缓存空间。

    后退n帧协议虽然效率高,可是遇到大场面,在网络比较差或者带宽比较低的状况,若是仍然使用这个协议会致使状况更加恶劣,这种状况停等协议虽然效率比较低,可是仍是比较适用的。


窗口的滑动

TCP提供体积可变的滑动窗口机制,支持端对端的流量控制:

  • TCP链接阶段,双方协商窗口的尺寸,同时接收方预留数据缓存区
  • 发送方根据协商的结果,发送符合窗口的尺寸的字节流,而后等待ack确认。
  • 发送方根据返回的确认信息,调整窗口的尺寸,调整包括,若是出现发送拥塞,发送窗口缩小原来的一半,同时将超时重传时间间隔扩大一倍,防止发生重传风暴。

在传输的过程当中,窗口是滑动的

看下图5-15,TCP链接阶段,双方协商窗口的尺寸,同时接收方预留数据缓存区


看图5-16,假设窗口的阈值是一半,因此A发送11个帧,发送后,等待确认,发送窗口位置不变。这时候发生了丢包,32,33没有收到。虽然31已经收到了,窗口理论上能够往右移动一个位置,可是为了节省宽带,不会每个帧都回复ack,而是累积几个以后在发出,因此31不会回复ack,窗口就卡在这了。


看图5-17,这时候30-33的已经确认了,因此窗口能够往右滑动三帧。37,38,40也许延迟还未收到。

看图5-18,在重传机制生效以前,A继续发送了后面的数据,这时候窗口已经所有用完,A会中止发送数据,等待B的窗口可用,B处理完以后会等待A发送数据,这样就形成了双方在等待,为了解决这个问题,TCP使用了Zero Window Probe技术,缩写ZWP。在窗口尺寸变成0以后,发送端会发送ZWP包询问接收端是否有足够的空间能够发送数据了,TCP使用持续计时器,若是结果仍然为0,则重置定时器继续等待。

丢包的缘由

  • 接收方缓存区满了
  • 信号差,波形失真
  • 包的校检失败
  • 网络拥塞

乱序的缘由

  • IP包是无序的
  • 中间件的内部调度,如路由器,路由器里面是有处理器,有些路由器使用多个流量处理单元,致使不一样包在不一样的处理单元,最后到达时间不同而发生了乱序
  • 多路复用,统一连接,不一样路径到达

TCP包头格式


标志位

  • SYN 用于链接请求时的标志,SYN = 1
  • ACK 用于确认成功接收数据,ACK = 1
  • FIN  用于链接释放的标志,FIN= 1
  • RST 用于重置一个异常的链接,接收端 告知 发送端 此链接有问题


  • PSH 用于通知接收端将缓存区的数据提交给上层,即便没有满
  • URG 用于通知接收端当前为紧急数据,将这个数据直接提交给上层,它不通过缓存区,后面的紧急指针表示紧急数据在当前数据的偏移位置

三次握手


  • 首先整个过程Seq都是动态生成的惟一序列号,不管谁发给谁,为了防止新链接和旧链接窜了。
  • ACK = 收到的Seq + 1
  • SYN = 1

链接过程的状态

  • 客户端SYN_SENT。客户端发送 SYN = 1,Seq = X 将状态设置为 SYN_SENT
  • 服务端SYN_RCVD。半链接状态,服务器收到后将状态设置为SYN_RCVD,并返回 SYN = 1,ACK= 1,Seq = Y,Ack = X + 1
  • 客户端ESTABLISHED。客户端收到后,状态设为ESTABLISHED,表示链接已创建。并发送ACK= Y + 1,Seq = Z
  • 服务端ESTABLISHED。服务端收到后,状态设为ESTABLISHED,表示链接已创建。

服务器维护了一个半链接的队列,该队列为每一个客户端的SYN包(SYN=X)开设一个条目,表示服务器已经收到SYN包,并向客户端发出确认,正在等待客户端的确认包。当服务器收到客户端的确认包时,删除该条目,该链接进入ESTABLISHED状态。

四次挥手


  1. FIN-WAIT-1。客户端中止发送数据,FIN=1,Seq=X(前面已经传送过来的数据最后一个字节的序号+1),客户端进入FIN-WAIT-1状态。
  2. CLOSE-WAIT。服务器发出Ack = X + 1,进入CLOSE-WAIT状态,通知应用程序,由于服务器是被动收到通知,此时服务可能数据还没发完,还要继续发送。
  3. FIN-WAIT-2。收到服务器的回复,再次等待服务器的关闭通知。这时候服务器还可能发着数据给客户端。
  4. LASK-ACK。服务器终于把事情处理完了,能够发出FIN = 1,Seq = Z,ACK = X + 1告知服务器断开链接,进入最后确认状态。
  5. TIME-WAIT,收到服务器的关闭请求,客户端回复ACK = 1,Seq = X + 1,Ack = Z + 1,这时候客户端不会立刻释放链接,它会等待2MSL(报文最长存活时间),防止这个消息服务器没有收到,而这时服务器发出重传信息,客户端就能够即时响应。
  6. CLOSED,服务器收到消息后释放链接,客户端通过2MSL后也释放链接。

数据是如何传输的

两台电脑之间通讯都须要把数字信号01转化成电信号,再调制成电磁波(好比光)。电磁波自己没法承载信息的,可是咱们能够控制电磁波的变化(幅度AM,频率FM,相位PM),让这些变化能够表明0和1。也就是说在信号线中走的是电磁波,因此在布线的时候要注意线与线之间的串扰。

电磁波有不少频段好比2515MHz-2675MHz、4800MHz-4900MHz,在空气中存在不少不一样频段的波,因此须要进行定宽调频,也就是说肯定带宽,而后再进行滤波,所谓的滤波就是经过滤波算法,好比卡尔曼滤波,根据截止频率是否靠近特征频率以及衰减程度来分类的,最后转换成01信号。带宽又叫频宽是指在固定的的时间可传输的资料数量,亦即在传输管道中能够传递数据的能力。在数字设备中,频宽一般以 bps表示,即每秒可传输之位数。

截止频率

用来讲明电路频率特性指标的特殊频率。当保持电路输入信号的幅度不变,改变频率使输出信号降至最大值的0.707倍,或某一特殊额定值时该频率称为截止频率。在高频端和低频端各有一个截止频率,分别称为上截止频率和下截止频率。两个截止频率之间的频率范围称为通频带。

将信号转化成字节,再将字节组装成帧。再以太网链路上的数据包被称为以太帧,在802.3标准理,规定了一个以太帧的数据部分(Playload)的最大长度是1500个字节(MTU),另外,以太网帧最小长度为64字节。

相关文章
相关标签/搜索