传输层
2022-06-05
-
传输层为运行在不同的主机上的进程提供了一种逻辑通信机制。
-
发送方将应用递交的消息分成一个或多个segment,并向下传给网络层;接收方将接收到的segment组成消息,向上交给应用层。
-
传输层协议分类:
- 可靠、按序的交付服务(TCP),提供拥塞控制、流量控制和连接建立。
- 不可靠的交付服务(UDP),基于尽力而为的网络层没有做可靠性方面的扩展。
-
接收端进行多路复用,传输层依据头部信息将接收到的segment交给正确的socket;发送端进行多路复用,多个socket为每个数据块封装头部信息,生成segment,交给网络层。
-
每个数据报携带源IP地址、目的IP地址,每个数据报携带一个传输层的端(Segment),每个段携带源端口和目的端口。主机收到segment后,传输层协议提取IP地址和端口信息,将segemnt导向相应的socket。
-
UDP的SOCKET用二元组标识(目的IP地址,目的端口号),来自不同源IP地址和端口号的IP数据报被导向同一个Socket,TCP的SOCKET用四元组标识(源地址,源端口,目的地址,目的端口)。
UDP #
-
- UDP(USER DATAGRAM PROTOCOL)基于IP协议,简单的包装了下IP协议,提供了传输层的复用、分用,同时提供了简单的错误校验。
- UDP段可能会丢失、错序。常用于流媒体应用。
- UDP校验和提供了差错校验功能。
可靠数据传输 #
- 可靠指的是不错、不丢失、不乱序。
- 通过使用校验和来检查位错误来保证不错,同时使用ACK(acknowledgement)来显式的告诉发送方已经正确的接收分组。
- 重传可用保证不丢失,对于未收到ACK的分组,进行重传,重传需要使用定时器,当超过一定时间未收到ACK则重传。
- 简单的重传可能会导致重复分组或乱序,需要使用序列号,发送方给每个分组增加序列号,接收方通过序列号来确定分组顺序。
流水线机制 #
- 简单的停-等协议效率很低,需要使用流水线机制来提高资源的利用率。
- 例:1Gbps(R)的链路,15ms(RTT)的端到端的传播延迟,8Kb(L)分组。
-
- 使用流水线机制
-
滑动窗口协议 #
- 包括GBN(go back N)和SR(selective repeat)。
GBN #
- 分组的头部中包含K-bit的序列号。窗口尺寸为N,最多允许N个分组未确认。ACK(n)表示序列号n(包括n)之前的分组均已被正确接收。
- 只为序列号最小的那个未收到ACK的分组设置计时器。
- 当发生了超时事件,即序列号n的分组未收到对应的ack时,会重传序列号大于等于n的所有分组。
- GBN发送方的FSM。base表示当前滑动窗口的起始位置,nextseqnum表示发送的分组的位置,下面的介绍是并行进行的。
- 当序列号小于滑动窗口的右边界时,会持续发送分组,直到达到滑动窗口的右边界。此时会启动定时器并拒绝上层协议发来的数据。
- 当定时器超时时,会重新发送滑动窗口左边界开始的窗口中的所有数据。
- 当正确接收到ack时,滑动窗口会向右移动,同时重新启动定时器;当数据已经发完了时,会关闭定时器。
-
- GBN接收方的FSM
- GBN只发送拥有最高序列号的、已被正确接收的分组的ACK,这就意味着序号为n的分组被正确接收时,序号小于n的所有分组都被成功接收。
- 对于乱序到达的分组,接收方会直接丢弃,并且为最近按序接收的、序列号最大的分组重新发送一个ACK。
-
- 案例
- 分组0和分组1均被正确接收,分组2由于丢失了。发送方发送过去的分组3、分组4、分组5,接收方均重发ACK(1),当一段事件后发送方一直未收到ACK(2),所以会重新发送分组2、分组3、分组4、分组5。
-
SR #
-
GBN单个分组的差错就能引起大量分组的重传。选择重传能仅让发送方重传个别它怀疑在接收方出错的分组,避免了不必要的重传。
-
SR接收方确认一个正确接收的分组而不管其是否按序,失序的分组将被缓存直到所有的丢失分组(序号更小的分组)都被收到为止。
-
-
序列号的空间大小必须大于等于窗口长度的两倍。
-
例:当窗口大小为4,序号大小也为4,发送方连续发送4个分组,接收方收到4个分组后,返回4个ACK,窗口已经向右滑动了4个。此时假如4个ACK都丢了,发送方超时后重新发送4个分组,此时接收方把分组0、1、2、3当作新的分组,就会导致错误。
-
-
例:当窗口大小为4,序号大小为5,发送方连续发送4个分组,接收方收到4个分组后,返回4个ACK,窗口已经向右滑动了4个。此时假如4个ACK都丢了,发送方超时后重新发送4个分组,此时接收方把分组0、1、2当作新的分组,就会导致错误。
-
-
例:当窗口大小为4,序号大小为7,发送方连续发送4个分组,接收方收到4个分组后,返回4个ACK,窗口已经向右滑动了4个。此时假如4个ACK都丢了,发送方超时后重新发送4个分组,此时接收方把分组0当作新的分组,就会导致错误。
-
TCP #
- 一个应用进程向另一个应用进程发送数据之前,会现在两个进程之间建立一条逻辑链路。当一端通过套接字传递数据,TCP将这些数据引导到该连接的发送缓存中,发送缓存时三次握手期间设置的缓存之一。接下来TCP会不时从发送缓存中取出一块数据,并将数据传送到网络层。
- TCP从缓存中取出并放入段中的数据大小受限于MSS(maximum segment size,即最大报文段长度)。MSS通常根据MTU(maximum Transmission Unit,最大传输单元)来设置。通常MTU为1500字节,TCP首部一般20字节,IP首部一般20字节,所以MSS是一般情况为1440字节。
TCP报文段结构 #

- 32位的序号和确认号用来实现可靠数据传输。
- 16位的接受窗口字段用来进行流量控制。
- 4位的首部长度用来指示以32bit的字为单位的TCP首部的长度。
- 可选和变长的选项字段,在协商MSS或调节窗口因子时使用。
- 6位的标志字段。ACK用于指示确认号的值是有效的,即该报文段包含一个对已被接收报文段的确认。RST、SYN、FIN用于连接的建立和拆除。
序号和确认号 #
- 一个报文段的序号是报文段首字节的编号,TCP连接双方都会随机地选择初始序号。例:假如MSS为1000,一个数据流的大小为5000字节,初始序号为234。则第一个报文段的序号为234,第二个报文段的序号为1234,第三个报文段的序号为2234。
- 确认号是接收方期望从发送方接收到的下一个字节的序号。TCP是累计确认的,如果收到了确认号为2234的报文段,则说明2234(不包含2234)之前的报文段都被成功接收。
往返时间的估计和超时 #
- TCP采用超时重传机制来处理报文段的丢失问题。超时时间间隔必须大于连接的往返时间(RTT),否则会造成丢包。
- SampleRTT是某报文段从发出到对该报文段的确认被收到之间的时间量。大多数TCP的实现是在某个时刻为一个已发送但未被确认的报文段估计SampleRTT,TCP不会对已被重传的报文段计算sampleRTT。
- 由于sampleRTT可能会有大的波动,TCP会维持一个EstimatedRTT,一旦获取一个新的sampleRTT,TCP会按照如下公式更新EstimatedRTT。α的推荐值为0.125。
EstimatedRTT = ( 1 - α ) * EstimateRTT + α * SampleRTT
- DevRTT用来计算sampleRTT偏离EstimatedRTT的程度, β的推荐值为0.25。
DevRTT = ( 1 - β ) * DevRTT + β * | SampleRTT - EstimatedRTT |
- 超时时间TimeoutInterval的计算如下,推荐初始的TimeoutInterval为1秒。当收到报文段并更新EstimatedRTT时,就会更新TimeoutInterval。
TimeoutInterval = EstimatedRTT + 4 * DevRTT
- 当出现超时后,会直接把TimeoutInterval加倍。例:假设当前的过期时间为0.75,当定时器超时后,TCP会重传报文段,并把过期时间设置为1.5s,当再次过期时,TCP会重传报文段,并将过期时间设置为3s。
可靠数据传输 #
- 快速重传是指如果TCP发送方接收到对相同数据的3个冗余ACK,即收到了一个正常的ACK(n)和三个冗余的ACK(n)时,TCP会重传序号为n的段,即使当前未超时。
-
- TCP采用累积确认,当受到ACK(n)则说明n之前的字节(不包括n)都已成功收到,存在如下的三种情况。
-
-
流量控制 #
-
一台TCP连接的每一侧主机都为该连接设置了接受缓存,为了防止缓存溢出,TCP提供了流量控制服务(flow-control service)。
-
TCP的发送方也可能因为IP网络的拥塞而遏制,这种控制方式为拥塞控制(congestion service)。
-
TCP通过让发送方维护一个叫接收窗口(Receive Window)的变量来提供流量控制,该字段是接收方的剩余缓存空间大小。因为TCP是全双工的,连接两端都会维护接收窗口。
-
假设主机A向主机B发送一个文件,主机B的接收缓存大小为RcvBuffer,LastByteRead用来表示主机B的应用程序从缓存中读到的最后一个字节编号,LastByteRcvd用来表示主机A发送到主机B且放入到接收缓存的最后一个字节的编号。
-
接收窗口rwnd的大小的计算如下,该字段是动态变化的,最开始rwnd等于RcvBuffer。
#接收窗口大小 = 接收缓存总大小 - 已接收但是未读的数据
# 1. 如果发的数据快,但是读数据慢,接收方来不及处理时,导致接收窗口变小
rwnd = RcvBuffer - ( LastByteRecvd - LastByteRead )
- 主机B通过把rwnd放到它发送给主机A报文段的接收窗口字段中,通知A该连接中还存在多少的可用缓存。主机A会跟踪两个变量,LastByteSent用来表示最后发送的一个字节编号,LastByteAcked用来表示最后一个确认的字节编号,通过如下关系来保证发送的数据不会造成缓存溢出。
#接收窗口大小 >= 未确认的数据
# 1. 当接收窗口变小后,发送方已发送但未确认的这部分数据减少
# 2. 当接收窗口大小为0时,发送方停止向接收方发送数据,但是还是会发送特殊的段,以便获取rwnd。
LastByteSent - LastByteAcked ≤ rwnd
- 为了避免主机B的接收缓存已满,然后发送给主机A rwnd=0,此时主机A不会在给主机B发送数据的情况,TCP要求当主机B的缓存已满时,主机A继续发送只有一个字节数据的报文段。这些报文段会被接收方确认,等主机B的缓存空间不为0时,会发送给主机A非0的rwnd值。
TCP连接管理 #
-
三次握手
-
- 客户端会像服务端发送一个特殊的报文段,该报文段不携带任何数据,SYN标志位被置为1,并且会随机选择一个序号client_isn,发送给服务器。该报文段被称为SYN报文段。
- 当该服务端收到SYN报文段后,为TCP连接分配缓存和变量,并向客户端发送报文段,该报文段SYN标志位置为1,并随即生成一个序号server_isn,同时ACK标志位置为1,确认号填client_isn+1,改报文段不包含任何数据。该报文段被称为SYNACK报文段。
- 客户端收到SYNACK后,为TCP连接分配缓存和变量,向服务端发送报文段,该报文段可以携带数据,SYN标志位被置为0(因为连接已建立)。同时ACK标志位置为1,确认号填server_isn+1。
-
TCP连接关闭
-
- 当客户端发起关闭连接时(服务端也可以发起),会向服务端发送一个特殊报文段,该报文段的FIN报文段被置为1,同时生成一个seq序号y,发给服务端。其实此时ACK标志位也会被置为1,用来确认上一次发来的数据。
- 服务端收到后,会将ACK标志位置为1,ack填y+1。
- 服务端会重复1~2步。
- 一次HTTP请求的连接过程,第三次握手时就已经开始带上数据了。
-
- 洪范攻击(SYN flood attack)指攻击者发送大量的TCP SYN段,却不完成第三次握手,由于服务端在第二次握手就开始分配资源,导致服务端资源被消耗殆尽。一种有效的防御机制SYN cookies能解决这个问题,】工作方式如下:
- 当服务端收到一个SYN段时,它不会开启一个半开的连接。它会根据源和目标的IP和端口以及秘密数通过散列函数来生成一个初始的TCP序号,这个序号被称为"cookie",服务端将这个特殊的SYNACK段发给客户端。
- 当服务端收到一个ACK时,通过散列函数来计算一个值,如果该值加1等于ACK,则说明改ACK是对之前的某个SYNACK的确认,服务端会生成一个具有套接字的全开链接。
- 如果客户端没有返回一个ACK,对服务器也没有影响。
- 当一台服务器接收到了一个TCP报文段,该报文段的目的端口或源IP与服务器上的套接字都不匹配时,服务器会向源发送一个特殊的重置段,该段的RST标志位被置为1。当一台主机接收到了一个UDP分组,它的目的端口与主机上的套接字都不符合,主机会发送一个ICMP数据报。
TCP拥塞控制 #
- 运行在发送方的TCP拥塞控制机制跟踪一个额外的变量拥塞窗口cwnd(congestion window),它对TCP发送方能向网络中发送的流量进行了限制,即:
LastByteSent - LastByteAcked ≤ min { rwnd, cwnd }
- TCP拥塞控制算法:1. 慢启动;2. 拥塞避免;3. 快速恢复。
慢启动 #
- 当TCP连接开始时,cwnd通常设置为MSS(存疑),这使得初始的发送速率约为MSS/RTT;
- TCP向网络中发送第一个报文段并等待一个确认,当确认到达时,将cwnd增加一个MSS;并发送出两个段,当着两个段被确认时,每个确认都将使cwnd增加一个MSS,这使得现在cwnd变成了4个MSS。总结:每经过一个RTT,
cwnd = cwnd * 2
。
-
-
拥塞窗口不会无限增大:
- 如果发生了丢包事件,TCP发送方将cwnd设置为1并重新开始慢启动过程,并设置ssthresh(慢启动阈值)的值为cwnd/2,当达到ssthresh后,cwnd线性增长;
- 如果检测到3个冗余ACK(连续收到4个相同的ACK,重复的ACK表示网络有能力来传输段)时,cwnd减半,并开始线性增长。(TCP RENO)
- 如果检测到3个冗余ACK,将cwnd设置为1(TCP Tahoe)
-