14周了,哥们儿学会儿吧别真挂了
更多是个人理解和总结,不保证正确性。

概要

  1. 传输层上接应用层(代表:HTTP协议),下接网络层(代表:IP协议)。主要提供可靠传输和复用分用的功能。
  2. 代表协议:TCP协议和UDP协议

复用分用:区分进程

复用分用即同一源主机上的不同进程与同一目的主机上不同进程通信时,共用同一网络连接。接收端传输层需要对IP层拿到的数据包进行区分并为上层应用提供服务,这是通过端口号来实现的。即网络层通过IP唯一标识主机,传输层用IP+端口号唯一标识进程。

差错检验:保证数据在传输过程不被破坏

TCP与UDP差错检验均类似,按照以下步骤:

  • 校验和字段清0
  • 填充0,保证IP数据包+协议首部+伪首部为16位整数倍
  • 16位为一组累加,高位溢出即补到低位上
  • 最终结果取反写回校验和字段

UDP协议

  1. 特点:不可靠、非连接,支持组播通信,多用于视频、音频流
  2. 实现差错检测(IPv4可选,IPv6强制)、复用分用功能
  3. 注:计算校验和时,目的主机的IP地址UDP通常知道,源IP的使用需要通过路由选择决定
    UDP比较简单,就是白给

TCP协议

真正的大爹来了
基本特点:字节流服务,可靠传输、面向连接、点对点通信,复用分用,流量控制和拥塞控制,通过四元组(源ip+端口、目的ip+端口)标识一个TCP连接

可靠传输

  • 提供差错检测(校验和)功能,正确接收返回确认
  • 使用序列号检测丢失和乱序
  • 超时重传机制,解决出错、丢失问题
  • 支持流水线机制,自适应窗口

发送端

TCP可靠传输
基本逻辑:仍使用滑动窗口,维护SendBase,NextSeq变量,来表示发送已确认,发送未确认的数据序列号。窗口大小由流量控制和拥塞控制情况来决定。采用累积确认机制,acknum=x代表x字节以前(包括x)的数据全都正确收到。seqnum=x代表数据包第一个字节的序号为x。基于此,发送端为每一个数据包设置定时器,如果收到了acknum=x的ACK回复,则取消x以前的所有定时器,同时SendBase增加,窗口右移。如果某个数据包超时了则重传该包。

接收端

首先需要计算校验和保证数据都无误。接收端无非是维护一个期望序列号的变量,如果收到的数据包小于它就直接丢弃,然后回ACK,告诉发送端在此之前的都收到了,然后现在希望收到这个期望序列号开头的数据包;等于的话就增加期望序列号的值,并缓存下这个数据包,后续拿给上层应用;如果大于则说明期望序列号的数据包丢失或者失序,仍然回复期望序列号的ACK,然后丢弃或者缓存该包(是否支持选择确认)。

基于上述逻辑,基本的可靠传输功能已经得到保证,下面主要是对性能进一步优化和改进,即做题做对了还不行,还有做得快,多快好省(雾)

几种特殊机制:延迟确认、快速重传和选择确认

问题:发送端发一个包,接收端回一个ACK,效率较低,且容易造成网络拥塞。
解决:接收端延迟确认,即从收到第一个期望数据包开始设置一个500毫秒的定时器,在此过程中如果收到更多期望的数据包则更新acknum。等到500毫秒结束再发回ACK包。本质上,这是做的正确性是由累积确认的机制决定的,即acknum=x代表在此之前的都收到了。接收端发一个ACK包一次性确认多个包。

问题:传输过程中某一个包丢失了,后续包都正确抵达,但因为这一个包的丢失发送端又需要重传所有后续数据包。
解决:接收端采取选择确认。即缓存不连续的数据包。建立连接时在选项部分通告是否支持选择确认。若支持,则接收端的处理逻辑需要修改,收到的数据包序列号大于期望序号的时候需要缓存,发ACK仍未期望序列号的ACK。若之后的数据包填补了空缺,则期望序列号直接累加。

问题:重传丢失的TCP段之前引入较长的延时,即超时时间较长,每次都等待,效率较低。根据基本的协议约定,如果某个包丢了,后续包又抵达了接收端。接收端会不断发送期望序列号的ACK。能够利用这一点进行优化?
解决:发送端快速重传机制。如果单个包或者少量数据包丢了,根据协议,发送端收到三次重复ACK,则说明接收端期望的包丢了,发送端直接重传此包,而不需要等待定时器超时。如果是某个时刻网络直接断开连接了,后续包也无法抵达,那么快速重传机制也无能为力。注意,多次超时重传如果还是不能收到ACK,则发送端会主动断开连接。

GBN协议在传输开始即设定了窗口大小,TCP协议的不同在于传输过程中动态调整窗口大小。其实际的窗口大小取决于流量控制窗口和拥塞控制窗口中的较小值。

建立连接

没什么好说的,三次握手,看图吧
三次握手

断开连接

四次挥手

总的状态机如下:
客户端
服务端

流量控制

流量控制用于控制发送方和接收方之间数据传输的速率,以避免发送方发送数据过快导致接收方来不及处理。接收端利用“接收窗口通告”域段告知发送端接收端缓冲区剩余的空间,发送端依据该通告调整发送窗口的大小。如下例:
流量控制

拥塞控制

简单理解,网络传输就是开车从一个地方到另一个地方,网络拥塞就是发生堵车了。拥塞控制无非就是尽量避免堵车。底层的物理链路类似于实际的公路,带宽类似于几车道,带宽多了就允许更多的车上路。传输层进行拥塞控制,无非是堵车的时候少让一些车上路,不堵的时候多放一些车出来,对应到TCP协议就是控制发送窗口大小。依据实时状况调整窗口。

还是放个定义,网络拥塞:主机发送的数据过多或过快,造成网络中的路由器(或其他设备)无法及时处理,从而引入时延或丢弃

其实对于拥塞问题,我感觉从网络层入手也是一个不错的方向。以下内容严重夹带个人私货在传统路由算法中,路由表依据网络拓扑图来选择下一跳的路由地址。我们的目标是将数据包从源主机以最短时间送到目的主机,传统路由模式用Dijkstra算法来计算拓扑图中两点之间的最短路径,但这其实是带宽空闲的理想情况下的最佳选择。在实际情况中,实时拥塞状况也是影响因素之一。这就好比用导航软件从A到B,有一条最短的路线,但一看堵车堵得严重,这时候大可选择另一条相对较长但没这么堵的路线。这样做之后能够充分利用网络的带宽,同时实现负载均衡,避免某些链路过载而某些链路空闲的情况发生。但也会有一系列的问题产生,网络作为一个分布式系统,没有一个类似于高德地图的东西来告诉路由器或者源主机当前网络的“路况”,收集整个互联网的实时带宽太困难,同时链路故障和动态变化,带宽信息的延迟问题也很难解决。

可以看到,网络拥塞的问题不仅仅是传输层所特有的,在整个计算机网络结构中都存在。底层可以不断更新技术,增加带宽,上层通过优化协议设计和路由算法,从多个层次来应对拥塞问题,优化网络整体性能。

传输层两类拥塞控制策略:

  • 端到端拥塞控制:网络中无明确的反馈,端系统通过观察丢失、延迟推断是否发生拥塞,TCP采用该策略。
  • 网络辅助的拥塞控制:路由器提供到端系统的反馈,或者接收端返回ACK的时候指示拥塞情况。

Reno算法

目标:既不造成网络严重拥塞,又能更快地传输数据
问题:发送多快比较恰当?
基本思想:

  • ACK返回:说明网络并未拥塞,可以继续提高发送速率
  • 丢失事件:假设所有丢失是由于拥塞造成的,降低发送速率

将基本思想定量化,Reno算法如下:
MSS:每次发送TCP数据包的最大长度
cwnd:拥塞窗口大小
ssthresh:阈值

慢启动阶段
初始拥塞窗口:cwnd=1(MSS)
每个RTT,cwnd翻倍(指数增长)
即每接收到一个ACK,cwnd增1(MSS)

  • 如果cwnd==ssthresh,则进入拥塞避免阶段
  • 如果发生超时丢失,则ssthresh=cwnd/2,cmnd=1,继续保持在慢启动阶段
  • 如果检测到三次重复ACK,则ssthresh = cwnd/2,cwnd= ssthresh+3,进入快速恢复阶段

拥塞避免阶段
每个RTT,cwnd增1(线性增长)
即每接收到一个ACK,cwnd增加MSS*MSS/cwnd的大小

  • 如果发生超时丢失,则ssthresh=cwnd/2,cmnd=1,进入慢启动阶段
  • 如果检测到三次重复ACK,则ssthresh = cwnd/2,cwnd= ssthresh+3,进入快速恢复阶段
    TCP Tahoe算法则是对于以上两种丢失情况均将cwnd设成1,并进入慢启动

快速恢复阶段
更像是一个过渡态。

  • 如果仍然收到重复ACK,则cwnd=cwnd+1(MSS)
  • 如果接收到新的ACK,则进入拥塞避免阶段,cwnd置为ssthresh
    RENO
    我个人以为这个算法更多偏向于经验性质,貌似没有很严谨的理论来支持算法本身的正确性,可能就是算法这样跑下来效果还不错。对于这种启发式的东西,也许可以“炼个丹”,加点机器学习的东西进去。基于以往的数据选择更优的窗口大小。

其他

还有一些需要考虑的问题:

RTO(超时重传时间)的设置

  • RTO设置过大,对于丢失的报文段重传等待的时间过长,对于应用来说会引入较大的时延
  • RTO设置过小,可能会提前超时,引入不必要的重传,浪费带宽资源

有几个不同的算法模型,这里不写了,都是带公式。总体来说RTO也是基于往返时间RTT来确定。基于过往的以及上一次最新的。照样的,这种需要预测未来的事我觉得也可以用机器学习炼个丹。

TCP洪泛攻击
也称Ddos攻击,即攻击者发送大量SYN数据包请求来消耗服务器的资源,服务器回复SYN+ACK后攻击者并不回复ACK,连接处于半开放状态,消耗服务器资源,导致普通用户连接不上服务器。解决的话,也许CDN是个不错的方法。

头阻塞问题
TCP向上层应用按序交付,如果之前一个包丢失或延迟,后续到达的数据包即便使用选择确认,也只是放在接收缓冲区。需要全部到达后再拿给上层应用。而缓冲区大小有限,头阻塞会影响传输性能。解决的话,使用多TCP连接,或设计UDP之上的可靠数据传输,如QUIC协议。

公平性问题

  1. UDP与TCP的公平性问题,简单来说就是UDP不进行拥塞控制,只要有数据就使劲传,纯粹流氓,TCP过于优雅,抢不过UDP。
  2. 多TCP连接的公平性问题:每个应用开一个TCP连接,但某个应用开了10个该怎么办?