Chapter 3 传输层
3.1 概述和运输层服务
运输层的功能:为不同主机上运行的应用进程之间提供逻辑通信
工作内容:
- 发送方:将应用数据划分为报文段,交给网络层
- 接收方:将报文段重组成应用数据,交付给应用层
运输层和网络层的区别:
- 网络层:是不同主机之间的逻辑通信,网络层只负责将一个主机上的报文成功发送到另外一个主机,至于应该由主机上的哪一个进程接收,是运输层需要考虑的事情。
- 运输层:是不同应用进程之间的逻辑通信。
- 不同的运输层协议可能提供不一样的服务
- 运输层协议能够提供的服务收受到底层网络协议的服务模型的限制
- 在网络层不提供某些服务的情况下,需要由运输层自己提供
端口:让应用层的各种应用进程都能将其数据通过端口向下交付给运输层,以及让运输层知道应当将其报文段中的数据向上通过端口交付给应用层相应的进程(或线程)。从这个意义上讲,端口是用来标志应用层的进程(或线程)。端口使用16bit端口号标识。
3.2 多路复用和多路分解
套接字:TCP连接的端点。TCP使用连接而不仅仅是端口作为最基本的抽象。套接字将IP地址和端口号整合在一起。
报文段的发送:
- 主机接收到IP包
- 每一个数据包都有源IP地址和目的IP地址
- 每一个数据包都携带一个传输层的数据报文段
- 每一个数据报文段都有源、目的端口号
- 主机根据“IP地址+端口号”将报文段定向到对应的套接字。
无连接的运输层协议
创建的套接字具有主机本地端口,创建数据报发送到UDP套接字时,必须指定目的地IP地址和目的端口。UDP数据报仅有本地的端口号和远程端口号,并不包含本地和远程的IP地址。
当主机接收到UDP数据报,需要检查报文段的目的地端口,然后将UDP报文段发送给该端口号的套接字。
注意IP数据报与UDP数据报具有相同的目的端口,但不同的源IP和/或源端口号将被发送到目的地址相同的套接字。对于UDP,发给同一个进程的数据,无论是从哪来,都只用一个套接字来接收。也即在一台主机上发送UDP报文可以修改IP报文的IP地址,让目的主机误以为有多个IP的多个主机向它发送报文,但TCP不行。
有连接的运输层协议
TCP套接字由一个四元组标识(一个连接一组套接字),其中包含源和目的IP地址、源和目的端口号。
接收方主机根据这4个值将报文段定向到相应的套接字。服务器主机同时支持多个并发的TCP套接字,Web服务器为每一个客户连接都产生不同的套接字(非持久HTTP对每一个请求都会建立一个不同的套接字,会影响性能)。
3.3 无连接传输:UDP
UDP处理数据的流程(UDP无连接):
- 发送方
- 从应用进程获得数据
- 附加上为多路复用/多路分解所需的源和目的端口号以及差错检查信息,形成报文段。
- 递交给网络层,尽力而为地交付给接收主机
- 接收方
- 从网络层接收报文段
- 根据目的端口号,将数据交付给相应的应用进程
UDP的优势:
- 无需建立连接,可以减少时延
- 简单,发送方和接收方无需维护连接状态
- 段首部开销较小,UDP段首只有8字节而TCP有20字节
- 无拥塞控制,UDP可以随时按照需要发送
部分采用UDP协议的应用:
- 远程文件服务器
- 流式多媒体
- 网络电话(SNMP)
- 选录协议(RIP)
- 域名解析(DNS)
UDP滥用的后果:
- 路由器中的大量分组溢出,使得丢包率显著增加,反过来影响到UDP本身的传输效率
- 显著减小TCP的传输速率,甚至挤垮TCP会话
UDP也可以实现可靠传输,但是需要应用层进行辅助控制,需要应用层特殊的错误恢复,增加了应用进程的实现难度。
3.3.1 UDP报文段结构
UDP的报文段结构很简单,从前往后依次为:源端口号、目的端口号、长度、校验和、数据。其中长度是包含首部的长度,除了数据之外首部的4个控制结构各占16比特。
3.3.2 UDP检验和
UDP校验和提供差错检测功能,检验和用于确定当UDP报文段从源向目的地移动时,其中的比特是否发生了改变。
发送方对UDP校验和的计算方式:将报文段看做16比特一组的多组构成的序列,对报文的所有16比特字的和进行反码计算,获得校验码。如果在求和的过程中出现进位,需要提取进位并加到结果上。在校验和尚未计算时,校验和字段填充为全0进行计算,在计算完成后再用结果替换这里的全0。
接收方的验证方式:按照同样的方式以16比特为单位计算,如果最终结果为全1则认为没有错误(不是一定没有错误),否则认为有错误。
3.4 可靠数据传输原理
可靠数据传输的问题不仅在运输层出现,也会在链路层以及应用层出现。可靠数据传输队上层实体提供的服务可以抽象为:数据可以通过一条可靠信道进行传输。借助于可靠信道,传输数据比特就不会收到损坏或丢失,且所有数据都是按照发送顺序交付。
3.4.1 构造可靠数据传输协议
经完全可靠信道的可靠数据传输:rdt 1.0
最简单的情况:底层信道完全可靠。在底层信道可靠的情况下,发送端和接收端不需要进行另外的操作。
经具有比特差错信道的可靠数据传输:rdt 2.0
在分组的传输、传播或缓存的过程中,比特差错通常会出现在网络的物理部件中。
需要引入肯定确认和否定确认两种控制报文使得接收方可以让发送方知道哪些内容被正确接收。基于这种重传机制的可靠数据传输协议被称为自动重传请求(ARQ)协议。
ARQ协议中还需要:
- 差错检测:需要一种机制使得接收方检测到何时出现了比特差错。
- 接收方反馈:让接收方提供反馈信息给发送方确认。
- 重传:当接收方接收到异常的分组时发送方重传该分组。
上图解释:
- 发送方:
- 当上层调用时,高层调用rdt_send,低层首先计算校验值,然后发送。
- 如果接收到NAK,则重传。实现重传需要一个缓冲区保存未获得反馈的报文,长度只需要达到一个报文的大小即可。
- 如果接收到ACK,则待命。
- 接收方:
- 当接收到数据时,低层提取数据后传递给上层,上层计算校验值没有问题,让下层发送ACK。如果发现问题,让下层发送NAK。
注意:当发送方处于等待ACK或NAK的状态时,它不能从上层获得更多数据。因此发送方将不会发送一块新的数据,除非发送方确信接收方已经接收到当前分组。这种协议称为停等协议。
缺陷:没有考虑到ACK或NAK受损的可能性。
处理方案:
- 发送方和接收方交替重传报文,这样会陷入死循环。
- 增加足够的检验和比特使得发送方不仅可以检测差错还可以修复差错。
- 当发送方收到含糊不清的ACK或NAK时,只重传当前数据分组即可,这样会产生冗余分组。为了将该分组与新的分组区分,需要为数据包引入编号。(下一个版本的方法)
第二个版本:rdt 2.1
- 如果发送方接收到重复的ACK,当做NAK重传。
- 为每一个数据包加上序号。
- 接收方收到重复序号的数据会丢弃。
这里实际上将2个状态转换为4个状态,只是将相邻发送的数据包赋予不同的编号0和1。这样可以区分相邻两个数据包。
再次改进:rdt 2.2
去掉了NAK报文,只需要使用ACK报文即可。如果接收方接收到了受损的分组,可以对上一次正确接收的分组发送一个ACK,发送方接收到对同一个分组的两个ACK后就知道接收方有没有正确接收到跟在被确认两次的分组后面的分组。与2.1的细微变化在于:接收方此时必须包括由一个ACK报文所确认的分组序号(0或1),发送方此时必须检查接收到的ACK报文中被确认的分组序号。
信道丢包时的解决方案:rdt 3.0
发生丢包后的处理方法:校验和技术、序号、ACK、重传。
只需进行等待,就可以知道是否丢包。
相比较2.2,发送方增加了计时器,当等待时间过长时,重新发送数据包。
发送方需要等待:发送方与接收方之间的一个往返时延加上接收方处理一个分组的时间。这需要发送方明智地选择一个时间值来判断是否发生了丢包。
这里要尤其注意后面两种丢包情况的处理。
3.4.2 流水线可靠数据传输协议
rdt 3.0性能分析
这是一个停等协议,如果一个数据包的传输时延为10ms,传播时延为100ms,那么一个数据包发送完成至少需要210ms(忽略ACK报文的传输时延,RTT=200ms),这会使得信道在大部分时间处于空闲状态,在这210ms中如果一直传输数据,可以传输21个数据包,但这里只传输了1个。网络协议限制了物理资源的利用率。
改进方法:不使用停等协议,使用流水线技术。
流水线技术允许发送方发送多个数据包而无需接收方确认,因此编号不能只是0和1。如果在发送过程中出现错误需要重传,因此发送方需要缓存。如果需要处理失序的数据包,则接收方也需要一定的缓存。注意流水线模式中对于链路利用率的计算,分母的L/R是不用乘以分组长度的!
流水线技术的工作原理:
- 分组首部使用k-比特字段表示序号
- 未被传输和已被传输但还没有确认的分组的许可序号范围可以看做是一个在序号范围内大小为N的“窗口”。
根据流水线技术丢失分组的重传策略,可以将其分为GBN协议和SR协议,GBN协议其后分组全部重传,SR协议仅重传该分组。
3.4.3 回退N步
特点:
- 接收方对序号n之前包括n在内的所有分组进行确认,标志着序号n以及n以前的分组已经全部接收完成。
- 允许发送方能且只能连续发送n个数据包,若窗口大小为n。同时,窗口中未被确认的分组数量不能超过n。
- 对所有已经发送但未确认的分组统一设置一个定时器,从一次流水的最“老”分组开始计时。超时时重传分组n和窗口中所有序号大于n的分组。
- 接收方收到重复的分组时,会丢弃该分组并重发ACK,因此GBN协议中的接收方不需要缓存。
- 分组失序时,将失序的分组丢弃,并重发按序到达的最高序号分组的ACK。
- GBN协议在发送端的滑动窗口大小为2k-1,在接收端的大小为1。
3.4.4 选择重传
- 发送方
- 从上层收到数据,如果下一个可用于该分组的序号在窗口内,则将数据打包并发送。
- 为每一个分组定义计时器,超时时重传分组n并重置计时器。
- 如果收到在窗口编号范围内的ACK,则标记分组为已经接收,如果这个分组是窗口中的第一个分组,则将窗口的基序号前推到下一个未确认序号。
- 接收方
- 也定义一个窗口,用于接收。
- 如果接收到的数据包分组在窗口内,则发送ACK,如果失序则将其缓存。将该分组以及以前缓存的需要连续的分组一起交付给上层,将窗口前推到下一个未收到的分组。虽然曾经确认过,仍然再一次发送ACK。
- 否则忽略该分组。
接收方窗口必须小于或等于序号空间大小的一半,这样可以保证在窗口移动过程中,不会有相同序号的数据包在窗口内。因为如果ACK包丢失会导致接收方和发送方的窗口位置不同,全部ACK包丢失时,接收方的窗口在发送方窗口的前面,此时由于发送方没有接收到任何ACK,因此发送老编号的数据包,接收方需要保证此时其窗口中不含有对应该编号的数据包缓存。
当接收方窗口太大时,可能会导致发送方和接收方的发送和接收缺乏同步。窗口必须小于序号范围。
3.5 面向连接的传输:TCP
TCP是因特网运输层的面向连接的可靠的传输协议。
TCP连接仅存在于端系统,中间的路由器和交换机不知情。
TCP支持全双工服务。
TCP为点对点连接。
需要三次握手,具有最大报文段长度MSS。
3.5.1 TCP连接
TCP连接的建立过程:将发起连接的进程称为客户进程,另一个进程称为服务进程。客户首先发送一个特殊的TCP报文段,服务器使用另一个TCP报文相应,最后客户使用第三个特殊报文段响应。前两个报文不包含数据(有效载荷),第三个报文可以包含有效载荷。这被称为“三次握手”过程。
发送缓存:发起TCP三次握手期间设置的缓存之一。接下来TCP会不时从发送缓存中取出一块数据,并将数据传输到网络层。
最大报文段长度(MSS):通常根据最初确定的由本地发送主机发送的最大链路层帧长度(MTU)来设置。二者的计算公式是:MTU=MSS+TCP头长度+IP头长度。头部长度通常为40字节,以太网和PPP链路层协议的MTU均为1500字节,因此MSS的典型值为1460字节。
TCP为每块客户数据配上一个TCP首部,从而形成多个TCP报文段。
3.5.2 TCP报文段结构
- 源端口和目的端口:各占2字节。
- 序号:占4字节,TCP数据流中的每一个字节都会编上序号,这里的值指的是本报文段第一个字节在整个报文字节流中的序号。
- 确认号:占4字节,值为期望收到对方的下一个报文段的数据的第一个字节的序号。
- 首部长度:4比特,以32bit为单位的首部长度,为空时默认为20字节。
- 保留字段:6比特,目前无用。
- 紧急比特URG:为1时紧急指针标识该报文中紧急数据内容的地址。
- 确认比特ACK:为1时确认号字段才有效。
- 推送比特PSH:接收 TCP 收到推送比特置 1 的报文段,就尽快地交付给接收应用进程,而不再等到整个缓存都填满了后再向上交付。
- 复位比特RST:当 RST = 1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
- 同步比特SYN:同步比特 SYN 置为 1,就表示这是一个连接请求或连接接受报文。
- 终止比特FIN:用来释放一个连接。当FIN = 1 时,表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
- 窗口:2字节,控制对方发送的数据量,单位为字节。TCP连接的一端根据这个值设置自己的缓存窗口大小,然后通知对方以确定对方的发送窗口的上限。可用于流量控制。
- 校验和:2字节,校验包括首部和数据的所有内容,计算时需要在报文的最前面加上12字节的伪首部。
- 紧急指针字段:2字节,紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。
- 选项字段:长度可变,TCP只规定一个选项:MSS。其为数据段的最大长度。
- 填充字段:填充使得长度为32比特的整数倍。
3.5.3 往返时间的估计和超时
样本RTT:对报文段被发出到收到该报文段的确认之间的时间进行测量。样本RTT会有波动,要使得估算RTT更平滑,需要将最近几次的测量进行平均,而非仅仅采用最近一次的SampleRTT。
计算方式:估算RTT=(1-α)*估算RTT+α*样本RTT。这里α参考值为0.125。即测量的时间越久远,对估算RTT的影响越小。
估计估算RTT与样本RTT之间的偏差:偏差=(1-β)*偏差+β*|估算RTT-样本RTT|。β的参考值为0.25。第一次计算时偏差=0.5*样本RTT。
3.5.4 可靠数据传输
TCP的超时间隔设置为:估算RTT+4*偏差RTT。注意TCP只使用唯一的一个超时定时器。在超时时重传认为超时的定时器,并重启定时器。如果收到重复的ACK,则在更新sendbase之后,如果当前还有未确认的报文段,则也将定时器重置。当出现超时后,超时间隔值加倍。如果已经超时,再重传分组可能会加剧拥塞,这是一种形式受限的拥塞控制。
快速重传机制:超时周期往往很长,会影响到传输速度。可以通过添加重复的ACK检测丢失报文段。如果重复的ACK接收了超过3个,则认为需要重传。
3.5.5 流量控制
TCP流量控制的目标是当接收方处理速度较慢时,不至于让接收方缓存溢出。方法是接收方在反馈时将缓冲区剩余空间的大小填充在报文段首部的窗口字段中,通知发送方。
当接收方缓存满时,会通知发送方让其不再发送数据。而若接收方之后不发送任何数据给发送方,那么接收方缓存清空了发送方也无法知道。解决方法是发送方在知道接收方缓存为0之后持续发送数据长度为1的报文进行试探,如果缓存发生改变则接收方就不会发送rwnd=0的ACK。
3.5.6 TCP连接管理
TCP建立
- 客户端向服务端发送一个特殊的TCP报文段,其中不含应用层数据,但在报文段首部SYN比特置为1。这个报文被称为SYN报文段。之后客户端随机选择一个初始序号client_isn并将该需要放置于该起始的SYN报文段的序号字段中。该报文段会被封装在IP数据报中,并发送给服务端。
- 服务端接收到TCP SYN报文段,为该TCP连接分配TCP缓存和变量,并向该TCP客户发送允许连接的报文段,该报文段不包含任何应用层数据。该报文段的SYN置为1,确认号字段置为client_isn+1。最后服务器选择自己的初始序号server_isn并放置到序号字段。该报文段被称为SYNACK报文段。
- 收到SYNACK之后,客户为该连接分配缓存和变量。客户机向服务器发送另外一个报文段,对服务器的允许连接的报文段进行了确认,SYN置为0,负载可以有数据。
TCP释放
- 主机中的资源被释放,如果客户打算关闭连接,则客户TCP向服务器进程发送一个特殊的TCP报文段,FIN比特置为1。服务器接收到报文后向发送方回送一个确认报文段,然后服务器发送自己的终止报文段,其FIN比特置为1,最后由客户对服务器发来的报文进行确认。这即是四次挥手。
3.6 拥塞控制原理
当路由器缓存溢出时,会导致网络拥塞,造成丢包和时延增加。
3.6.1 拥塞原因与代价
情景1
两个发送方,两个接收方,一个具有无限大缓存的路由器,没有重传,忽略低层协议的影响,链路容量为R,两个发送方的发送速率相等。由于发送过程中路由器需要进行选路、缓存等操作,因此一个数据包从发送到接收并不是畅通无阻地行进在链路之中的。当链路越来越接近满负荷状态时,路由器的压力将会增加。虽然此时接收方依然可以以R的速度接收数据包,但是由于各种其他处理的时间积累,其排队的队列长度最终会积累到很大。
情景2
两个发送方和一台具有有限缓存的路由器。发送方对丢失的分组进行重传。
由于分组出现了重传现象,发送方的发送速率将大于接收方的接收速率。理想状态下,分组仅仅在丢失时才重传,这样可以让冗余的分组数量最少,但实际上有些分组可能会超时,此时进行重传就会增加冗余,占用链路资源。
此时拥塞的开销主要有:
- 发送方必须重传以补偿因为缓存溢出而丢失的分组
- 发送方在遇到大时延时所进行的不必要重传会引起路由器转发不必要的分组拷贝而占用其链路带宽。
情景3
四个发送方,每个主机都有相同的λi值,具有多跳路径,链路容量为R,会产生超时和重传。
当重传的数量过多时,既不能增加传输的速率,还占据了大量的链路资源,整个链路陷入崩溃。当分组被丢弃时,该分组曾用到的所有上游传输容量都被浪费了。
3.6.2 拥塞控制方法
- 网络辅助的拥塞控制:
- 直接网络反馈:路由器以阻塞分组的形式通知发送方“网络拥塞”
- 经由接收方的网络反馈:路由器标识从发送方流向接收方分组中的某个字段以指示拥塞的产生,由接收方通知发送方“网络拥塞”
- 端到端拥塞控制
- 网络层不为拥塞控制提供任何帮助和支持
- 端系统通过对网络行为的观测判断网络是否发生拥塞
- 目前TCP采用此方法
3.7 TCP拥塞控制
TCP拥塞控制的方法:
- 每个发送方自动感知网络拥塞的程度
- 发送方根据感知的结果限制外发的流量
- 如果前方路径上出现了拥塞,则降低发送速率
- 如果前方路径上没有出现拥塞,则增加发送速率
TCP发送方限制外发流量速率的方法
通过拥塞窗口控制。
LastByteSent-LastByteAcked<=CongWin
发送速率=CongWin/RTT bps
感知拥塞的方法:
- 超时
- 收到了三个冗余ACK
TCP检测到拥塞时如何控制
TCP拥塞控制算法(Reno算法),加性增,乘性减。
出现丢包事件后将当前CongWin大小减半,可以大大减少注入到网络中的分组数量。
当没有丢包时间发生时,每个RTT之后将CongWin增加一个MSS,使得拥塞窗口缓慢增大,以防止网络过早出现拥塞。
慢启动
建立连接时,CongWin = 1MSS
当可用带宽远大于MSS/RTT时,初始阶段以指数的速度增加发送速率,直到发生一个丢包事件为止。
即初始速率很低但是速率的增长速度很快。
拥塞避免
收到3个重复ACK时将CongWin减为原来的一半,线性增大拥塞窗口。
超时事件发生时,门限值设置为当前CongWin的一半(门限值初始值为65KB,即16MSS)
将CongWin设置为1个MSS大小。
窗口以指数速度增大,增大到门限值之后再以线性速度增大。
总结:
- 当拥塞窗口CongWin小于门限值ssthresh时,发送方处于慢启动阶段,窗口以指数速度增大。
- 当拥塞窗口CongWin大于门限值时,发送方处于拥塞避免阶段,窗口线性增大。
- 当收到3个重复ACK时,门限值设置为拥塞窗口的1/2,而拥塞窗口CongWin设置为门限值。
- 当超时事件发生时,门限值设置为拥塞窗口的1/2,而拥塞窗口CongWin设为1个MSS。
TCP的吞吐量
平均而言,吞吐量是丢包率L的函数:
3.7.1 公平性
目标:如果K个TCP连接共享同一个带宽为R的瓶颈链路,每个连接的平均传输速率为R/K。