计算机网络与通信笔记(三)
三、运输层
3.1 运输层服务
3.1.1 基本概念
- 运输层为不同主机上运行的应用进程提供逻辑通信信道$(logical\enspace communication)$
- 发送方把应用数据划分为报文段,交给网络层;接收方把报文段重组成应用数据,交付给应用层
- 网络层协议
- 网际协议$IP$是不可靠服务,它将尽力而为地在不同通信主机间交付报文段
- 但是它并不确保报文段的交付,不保证报文段按序交付,不保证报文段中数据完整性
- 运输层是应用进程之间的逻辑通信,网络层是不同主机之间的逻辑通信
- 运输层将两个端系统间$IP$的交付服务扩展为在端系统上的两个进程之间的交付服务
3.1.2 基本模型
- 假设家庭$A$的$6$个孩子要与家庭$B$的$6$个孩子相互写信
- 家庭$A$中的$Amy$负责收集所有信件并投递到邮局,并且负责将家庭$B$寄来的所有信件送到每个人手中
- 家庭$B$中的$Bob$负责收集所有信件并投递到邮局,并且负责将家庭$A$寄来的所有信件送到每个人手中
- 进程$= $孩子们
- 应用层报文$ = $信封中的信笺
- 主机$ = $家庭
- 运输层协议$ = $$Amy$和$Bob$
- 网络层协议$ = $邮局提供的服务
- $Amy$和$Bob$只在各自家里进行收发工作
- 运输层协议只工作在端系统中
- 假如$Amy$和$Bob$外出度假,分别替换成年龄较小的$Lisa$和$John$,他们可能会由于粗心大意丢失信件
- 不同运输层协议提供的服务模型不一样,如$UDP$和$TCP$
- 邮局不承诺信件送达的时间
- 运输层协议能够提供的服务受到底层网络协议的服务模型的限制
- 邮局不承诺信件一定安全可靠的送达,可能在路上丢失,但$Amy$和$Bob$可在较长时间内没有受到对方的回信时,再次誊写信件并寄出
- 在网络层不提供某些服务的情况下,运输层自己提供
3.2 多路分解和多路复用
3.2.1 基本概念
多路分解:将运输层报文段中的数据交付到正确的套接字的工作
多路复用:在源主机从不同套接字收集数据块,并为每个数据块封装首部信息(用于多路分解)生成报文段,然后将报文段传送到网络层
3.2.2 要求
- 套接字有唯一标识符
- 每个报文段有特殊字段指示该报文段要交付到的套接字
- 包括源端口号字段和目的端口号字段,各占$16\enspace bit$
- 其中$0\sim1023$范围的端口号称为周知端口号,保留给诸如$HTTP$、$SMTP$等周知应用层协议
3.2.3 无连接的多路分解与多路复用
- 一个$UDP$套接字是由一个二元组全面标识的,具体为(源端口号,目的端口号)
- 如果两个报文段具有不同的$IP$地址或源端口号,但是具有相同的目的$IP$地址和目的端口号,那么这两个报文段将通过相同的目的套接字被定向到相同的目的进程
- 具体过程
- 创建套接字:运输层自动为其分配一个端口号$(1024\sim65535)$,或者指定一个端口号
- 假设主机$A$中的一个进程具有$UDP$端口$19157$,欲发送一个报文给位于主机$B$中的另一进程,其具有$UDP$端口$46428$
- 主机$A$中的运输层封装报文,添加源端口号$19157$,目的端口号$46428$以及其他两个字段得到报文段
- 运输层将报文段传递到网络层,网络层封装$IP$数据包并尽力而为地传送到接收主机
- 如果报文段到达主机$B$,主机$B$中的运输层即检查目的端口号$46428$,并将报文段交付给端口号为$46428$的套接字
- 当主机$B$需要回发报文段给$A$时,即需要将来自A的报文段中的源端口号作为目的端口号发送报文段
3.2.4 面向连接的多路分解与多路复用
一个$TCP$是由一个四元组全面标识的,具体为(源$IP$地址,源端口号,目的$IP$地址,目的端口号)
与$UDP$协议不同,如果两个报文段具有不同的$IP$地址或源端口号,而且具有相同的目的$IP$地址和目的端口号,那么这两个报文段将通过不同的目的套接字被定向到不同的目的进程
具体过程
- 假设主机$A$中的一个进程具有$TCP$端口$19157$,欲发送一个报文给位于主机$B$中的另一进程,其具有$TCP$端口$46428$
- 同时主机$C$中的一个进程也具有$TCP$端口$19157$,也要发送报文给主机$B$中具有$TCP$端口$46428$的进程
- 主机$B$依然能够正确分解具有两个相同源端口号和目的端口号的连接,因为二者的$IP$地址不同,决定着其套接字不同
$Web$服务器与$TCP$
在$Web$服务器中,当客户发送请求时,所有报文段的目的端口号都将为$80$,这时服务器根据源$IP$地址和源端口号来区分来自不同客户的报文段
在当今的高性能服务器中,通常只使用一个进程,而是通过为不同的套接字创建新的线程(轻量级子进程)提供服务
非持久$HTTP$对每一个请求都建立不同的套接字,会影响性能
3.3 $UDP$协议
3.3.1 $UDP$报文段格式
- 长度字段指示了包括首部在内的报文段中字节数
- 校验和用于接收方校验报文段是否发生差错
3.3.2 $UDP$校验和
发送方
把报文段看作是16比特字的序列
对报文段的所有$16$比特字的和进行反码运算,加法有溢出时,需要将进位加到末尾
将计算校验和的结果写入$UDP$校验和字段中
接收方
- 将包括校验和在内的所有$16$比特字加在一起
- 如果没有差错,结果将为$1111,1111,1111,1111$
无法纠正错误
3.3.2 $UDP$与$TCP$对比
$UDP$ | $TCP$ | 说明 |
---|---|---|
无需建立连接 | 需要建立连接(握手) | 建立连接会增加时延 |
无需维护连接状态 | 需要维护连接状态 | |
首部$8\enspace Byte$ | 首部$20\enspace Byte$ | $UDP$段首部开销较小 |
无拥塞控制,可按需随时发送 | 有拥塞控制 | 大量使用$UDP$会导致路由器中堆积分组,挤占$TCP$会话 |
适用于$DNS$服务、因特网电话 | 适用于$Web$服务、电子邮件 |
3.4 可靠数据传输
3.4.1 可靠数据传输概述
可靠数据传输:数据不会丢失且数据不会出错
网络层的IP协议是不可靠信道,因此为了实现可靠数据传输,需要在运输层做出保证可靠数据传输的工作
可靠数据传输协议模型
使用有限状态机$FSM$描述发送方和接收方
- 在模型中,存在多个状态
- 事件引起状态的变化
- 状态变化过程中又会存在一系列动作的发生,以完成状态的转换
3.4.2 可靠信道上的可靠传输
信道模型:不会发生比特传输错误,不会造成分组丢失
有限状态机$FSM$
- 发送方——发送分组:发送报文段,继续等待上层调用发送分组
接收方——接收分组:分解得到数据
3.4.3 简单停等协议
信道模型:分组比特可能受损,但分组将按序接收,不会丢失
停止等待协议:每次发送分组后,发送方需要等待接收方的反馈
设想方案
- 第一步:判断分组受损——差错检测
- 第二步:通知发送方分组是否受损——接收方反馈(ACK与NAK)
- 第三步:得知分组受损$(NAK)$后,发送方的处理手段——出错重传
有限状态机$FSM$
- 发送方
- 发送分组:生成校验码$checksum$,用于进行差错检测,发送报文段,跳转到等待状态
- 反馈$ACK$:清除缓冲区中的报文段,跳转到等待上层调用发送分组的状态
- 反馈$NAK$:重新发送报文段(保存在缓冲区中),继续等待反馈
- 接收方
- 接收到的分组出错$(corrupt)$:生成$NAK$报文段,发送给发送方
- 接收到的分组正确$(notcorrupt)$:分解得到数据,生成$ACK$报文段,发送给发送方
- 发送方
新的问题:$ACK$和$NAK$分组也可能受损
- 受损的分组视为$ACK$不合适
- 受损的分组视为$NAK$可能导致接收方重复收到分组——对分组进行编号,便于接收方识别是新分组还是旧分组
改进后的有限状态机$FSM$
取消$NAK$
- 取消$NAK$,接收方对最后一个正确收到的分组发送$ACK$
- 同时,$ACK$中必须指出被确认分组的序号,以便于接收方标识正确收到了哪一个分组
- $Double\enspace ACK=NAK$
取消$NAK$后的有限状态机$FSM$
3.4.4 实用停等协议
信道模型:分组比特可能受损,还可能会丢包
如何检测丢包:耐心的等待——超时重传
有限状态机$FSM$
性能低下
- 信道利用率:传输时间/总时间(从发送方开始传输到发送方接收到反馈所用的时间)
- 假设某条$1Gbps$的链路,存在$15ms$的端到端时延,则传送$1KB$大小的分组所用的时间为$T_{trans}+RTT=\frac{1KB}{1Gbps}+15ms\times2=30.008ms$,也即链路速度被限制为$33KB/sec$的吞吐量
- 网络协议大大限制了物理资源的利用率,实际上用于传输分组的时间只占$\frac{0.008}{30.008}=0.00027$
3.4.5 滑动窗口协议
解决方案:允许发送方发送多个分组后再等待确认
- 必须增大序号范围
- 发送方和接收方需要对分组进行缓存
流水线技术工作原理
用$k$位进行序号编码
扩大发送方乃至接收方的缓冲区大小——窗口
当丢失一个分组后,如何进行重传
$GBN(Go\enspace Back\enspace N)$协议 | 选择重传$(SR)$协议 | |
---|---|---|
确认方式 | 累计确认 | 单个确认 |
定时器 | 对所有已发送但未确认的分组统一设置定时器 | 对所有已发送但未确认的分组分别设置定时器 |
超时$(n)$ | 重传分组$n$和窗口中所有序号大于$n$的分组 | 仅重传分组$n$ |
失序分组 | 丢弃(不缓存),接收方缓冲区大小为$1$个分组 | 缓存,接收方缓冲区大小与发送方一致 |
失序分组处理 | 重发按序到达的最高序号分组的$ACK$ | 对失序分组进行选择性确认 |
要求 | $W_s\le2^k-1,W_r=1$ | $W_s,W_r\le2^{k-1}$ |
分组序号长度与窗口大小的关系
- 假设分组序号为$k$位,发送窗口大小为$W_s$,接收窗口大小为$W_r$,发送窗口当前序号为$i,\cdots,i+W_{s-1}$
- 极端情况下,发送的所有分组均正常接收,但是$ACK$均丢失,则
- 发送窗口当前序号为$i,\cdots,i+W_{s-1}$
- 接收窗口当前序号为$i+W_s,\cdots,(i+W_s+W_{r-1})\enspace mod\enspace 2^k$
- 两个窗口序号不重复,且均在$[0,2^k-1]$内
- 要求$W_s+W_r\le2^k$
3.5 $TCP$协议
3.5.1 $TCP$工作流程
- 建立连接——三次握手
- 客户发送一个特殊的$TCP$报文段
- 服务器也发送一个特殊的$TCP$报文段作为响应
- 客户再发送一个特殊的报文段作为响应,可以承载有效负荷
- 发送数据
- 客户进程从套接字传递出数据流,经过该门后即进入$TCP$控制
- $TCP$将数据流引导至该连接的发送缓存中
- $TCP$每次取出一块数据放入报文段中进行运输,每次取出的数据数量受限于最大报文段长度$MSS$,而该值受限于最大链路层帧长度$MTU$(能从源到目的地的所有链路上发送的最大链路层帧)
- $MSS$指报文段中应用层数据的最大长度,而不包含$TCP$首部
- $TCP$是全双工的
3.5.2 $TCP$报文
序号:报文段的首个字节在整个字节流中的的序号,是离散型编号
假设数据流包含$500000$字节,$MSS$为$1000$字节,那么将构建$500$个报文段,其序号依次为$0$、$1000$、$2000$等等
确认号(期待号):期待得到的下一个字节的序号,当$ACK$字段为$1$时,确认号才有效
如确认号为$n+1$时表示接收方接收到第$n$号,期望得到$n+1$号分组,这称为累计确认
首部长度:$TCP$最长$60$个字节,以$4$个字节为单位进行递进,即与图示行数相同,取值为$[5,15]$
窗口:用于$TCP$流量控制
检验和:差错检测
紧急指针:当$URG$字段为$1$时,表示需要传送紧急数据;紧急指针指示了紧急数据的结尾
当$PSH$字段为$1$时,整个数据部分都为紧急数据
3.5.3 $TCP$机制
快速重传
- 原因:超时周期往往太长,增加重发丢失分组的延时
- 通过重复的$ACK$检测丢失报文段:如果发送收到一个数据的$3$个冗余$ACK$,即确认数据之后的报文段丢失,以在超时到来之前重传报文段
- 每次$TCP$重传都会将下一次超时间隔设置为先前值的两倍
流量控制
可变滑动窗口:接收方将缓冲区的空闲空间大小写入报文段返回给发送方,发送方根据空闲空间大小调整发送窗口大小
当发送方接收到空闲空间大小为$0$时,为避免进入假死状态(发送方不发送报文段,接收方不发送反馈),发送方会持续发送小的报文段试探接收方
当接收方重新获得空间空间后,小报文段将会被接收方响应处理并反馈空闲空间大小给发送方
拥塞控制
拥塞:包括丢包 (路由器缓冲区溢出)和时延长 (在路由器缓冲区排队)
- 当路由器缓存无限大且不会重传时,随着发送方速率的增大,接收方速率也会增大;但当接收方速率饱和时,吞吐量也随之固定。而此时,也就意味着在路由器缓冲区排队的分组越来越多,造成越来越大的排队时延
- 当路由器缓存有限且会对丢失的分组重传时,对延迟到达(而非丢失)的分组的重传使得发送方速率比理想情况下更大于接收方速率;发送方在遇到大时延时所进行的不必要重传会引起路由器转发不必要的分组拷贝而占用其链路带宽
- 当路由器缓存有限且会进行超时重传时,由于超时重传,当分组被丢弃时,该分组曾用到的所有上游传输容量被浪费
端到端拥塞控制
- 每个发送方自动感知网络拥塞的程度,发送方根据感知的结果限制外发的流量
- 如何限制外发流量:控制拥塞窗口长度
- 如何感知拥塞程度:超时或者$3$个冗余$ACK$
- 如何调节发送速率:加性增,乘性减(出现丢包事件后将当前$ CongWin $大小减半,可以大大减少注入到网络中的分组数;当没有丢包事件发生,每个$RTT$之后将$CongWin$增大$1$个$MSS$,使拥塞窗口缓慢增大,防止网络过早拥塞)
$Reno$算法
- 慢启动:$ CongWin = 1 MSS$,小于阈值$ssthresh$时指数增加
- 拥塞避免:达到$ssthresh$后,加性增
- 收到$3$个冗余$ACK$:$ssthresh=CongWin/2$,$CongWin=ssthresh+3MSS$,加性增
- 超时:$ssthresh=CongWin/2$,$CongWin=1MSS$,指数增加到阈值后加性增