运输层
从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务
属于面向通信部分的最高层,同时也是用户功能中的最低层。
只有位于网络边缘部分的主机的协议栈才有运输层,核心部分中的路由器只用到下三层的功能。
运输层功能
- 提供应用进程之间的逻辑通信(网络层提供的是主机之间的逻辑通信)
- 复用和分用。复用指发送方不同应用进程都可以使用同一个运输车协议传送数据;分用指的是接收方传输层剥去报文后能够把这些数据正确交付应用进程。
- 对报文进行差错检测(包括首部和数据部分)IP数据报不检测数据部分
- 提供两种不同的传输协议:面向连接的TCP和无连接的UDP
网络层通信 & 运输层通信$\star$
- 运输层为应用进程提供端到端的逻辑通信,网络层为主机之间提供逻辑通信;
- 运输层对收到的报文进行差错检测,包括首部和数据部分。而在网络层IP数据报首部中的检验和字段,只检验首部是否出现差错而不检验数据部分;
- 根据应用程序的不同,运输层需要有两种不同的运输协议,即面向连接的TCP和无连接的UDP,而网络层无法同时实现这两种协议。
运输层协议:UDP & TCP
UDP | TCP |
---|---|
无连接的协议,提供无连接服务 | 面向连接的协议,提供面向连接服务 |
数据单元TPDU是UDP报文或用户数据报 | 其传送的运输协议数据单元TPDU是TCP报文 |
支持单播、多播、广播 | 支持点对点单播,不支持多播、广播 |
不可靠交付 | 提供可靠服务 |
简单。适用于很多应用,如:多媒体应用等。 | 复杂。用于大多数应用,如:万维网、电子邮件、文件传送等。 |
面向报文 & 面向字节$\star $
- UDP是面向报文的。发送方UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。接收方UDP对IP层交上来的UDP用户数据报,在去除首部后就原封不动地交付上层的应用进程,一次交付一个完整的报文。
- TCP是面向字节流的。虽然应用程序和TCP的交互是一次一个数据块,但TCP把应用程序交下来的数据仅仅看成是一连串的无结构的字节流,但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。
运输层端口
端口:应用层应用进程数据通过端口向下交付给传输层;传输层知道将报文段数据通过端口上传应用层响应进程
端口号:应用进程通过端口号标识【端口长度16位;允许有65,535个不同的端口号】不同计算机的相同端口号是没有联系的
端口作用:对TCP/IP体系的应用进程进行统一的标志,使运行不同操作系统的计算机的应用进程能够互相通信。
端口类型
服务器端使用的端口号
- 熟知端口【0 ~1023】:已被指派给TCP/IP最重要的应用程序
- 登记端口号【1024 ~49151】:没有熟知端口号的应用程序使用使用这个端口号必须在IANA 登记,以防止重复
客户端使用的端口号(短暂端口号)【49152~65535】:客户进程选择暂时使用
客户端一定要提前知道服务端的端口
服务端大多数不需要提前知道客户端的端口
常用端口号
用户数据报协议UDP
仅在IP服务增加:端口复用和分用、差错检测应用几乎直接和IP打交道
使用UDP而非直接IP分组原因$\star$:
- IP分组包含IP地址,该地址指定目的主机,但当分组到达目的主机会不清楚交付哪个进程
UDP分组包含目的端口,使得分组被投送给正确的进程 - UDP可以对数据包做包括数据段在内的差错检测,而IP只对其首部进行差错检测
采用UDP原因$\star$
- UDP是无连接的,即发送数据之前不需要建立连接,因此减少了开销和发送数据之前的时延。虽然UDP提供的是不可靠的服务,但UDP没有拥塞控制,有时某些服务为达到较高的效率但同时对可靠性要求不高时,往往采用UDP协议。
- 例如视频会议,一定量的有差错或丢帧不会对画面产生太大影响,TCP数据报出错则会引起重传,可能带来较大的时延扰动,因此视频会议采用的是不可靠的UDP。
UDP优点
- UDP是无连接的:发送数据前不建立连接【减少了开销和发送数据之前的时延】
- UDP使用尽最大努力交付:不保证可靠交付【主机不需要维持复杂的连接状态表】
- UDP是面向报文的:一次交付一个完整的报文。
- UDP没有拥塞控制:网络拥塞不会使源主机的发送速率降低【对实时应用很重要,很适合多媒体通信的要求】
- UDP支持一对一、一对多、多对一和多对多的交互通信。
- UDP的首部开销小:仅8字节,小于TCP的20字节。
UDP的首部格式
伪首部:12字节,仅在检验和时临时连接,不算UDP真正首部
源IP地址:4字节
- 目的IP地址:4字节
0:1字节
- 17:1字节
- UDP长度:2字节
源端口:[16位]源端口号。在需要对方回信时选用。不需要时可用全0。
目的端口:[16位]目的端口号。这在终点交付报文时必须使用。
长度:[16位]UDP用户数据报的长度,其最小值是8(仅有首部)
体验和:[16位]检测UDP用户数据报在传输中是否有错。有错就丢弃。
若结果为全1时,不取反码(计算结果为0记为全1)
不适用检验和取全0
UDP校验和
- 添加伪首部
- 划分为16位字符串,数据字段不满16位则填0补充
- 按二进制反码求出16位字符串的和,填入校验和字段
- 接收方加上伪首部补零后,按二进制反码求和
- 如无差错则结果全1
- 若有差错,则丢弃该报文,或交付上层
传输控制协议 TCP
TCP特点
- 面向连接的运输层协议
- 每条TCP连接只能有两个端点,每条TCP连接只能是点对点的(一对一)
- 提供可靠交付的服务:无差错、不丢失、不重复、有序
- 提供全双工通信
- 面向字节流:TCP把应用程序交下来的数据块看成仅仅是一连串无结构的字节流
TCP报文段
TCP首部的最小长度为20字节,最长60字节
源端口 / 目的端口[16位]:运输层与应用层的服务接口,复用和分用功能都要通过端口才能实现
序号[32位]:TCP数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。
确认号[32位]:是期望收到对方的下一个报文段的数据的第一个字节的序号(确认号$N$表示到$N-1$为止字节都正确收到)
数据偏移(首部长度)[4位]:它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。
保留字段[6位]:置0
紧急URG[1位]:置1时,紧急指针有效,表明此报文段中有紧急数据,应尽快传送(相当于高优先级的数据).
确认ACK[1位]:置1时,确认号字段有效
推送 PSH[1位]:置1时,尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付
复位RST[1位]:置1时,TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须重新建立连接
同步SYN[1位]:置1时,表示这是一个连接请求或连接接受报文。
终止FIN[1位]:置1时,表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
窗口字段[16位]:接收方让发送方设置发送窗口的依据
检验和[16位]:检验的范围包括首部和数据这两部分。要在TCP报文段的前面加上12字节的伪首部。
紧急指针字段[16位]:指出在本报文段中紧急数据共有多少个字节
选项字段:长度可变。
- MSS——最大报文数据字段长度
- 窗口扩大选项——3字节。
其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口位数增大到(16+ S),相当于把窗口值向左移动S位后获得实际的窗口大小。 - 时间戳选项——10字节。其中最主要的字段时间戳值字段(4字节)和时间戳回送回答字段(4字节)。
- 选择确认选项
填充:使整个TCP首部长度为4字节的整数倍
TCP连接管理
TCP连接端点:套接字
工作方式:C/S——主动发起请求的是客户,被动等待连接的是服务器
三次握手建立连接
- SYN=1;seq=x不携带数据,但消耗序号
- SYN=1;ACK=1;seq=y;ack=x+1不携带数据,但消耗序号
- ACK=1;seq=x+1;ack=y+1
过程:
- 客户端:发送X
- 服务端:发送Y,确认X+1
- 客户端:发送X+1,确认Y+1
四次握手释放连接
- FIN=1;seq=u
- ACK=1;seq=v;ack=u+1
- FIN=1;ACK=1;seq=w;ack=u+1
- ACK=1;seq=u+1;ack=w+1
过程:
- 客户端:发送U
- 服务端:发送V,确认U+1
- 服务端:发送W,确认U+1
- 客户端:发送U+1,确认W+1
TCP的有限状态机
TCP 可靠传输
校验、序号、确认、重传
编号$\star$
只有对分组和确认分组进行编号,接收方才可以识别出重复帧,发送方才能明确是哪一个发送出去的分组收到了确认,而哪一个发送出去的分组还没有收到确认,所以在停止等待协议中应当使用编号。
确认
洗择确认SACK:中间缺少一些序号的数据,仅发送缺少的数据
- 和前后字节不连续的每一个字节块有左边界和右边界
- 由于首部长度最多只有40字节,选项中最多只能指明4个字节块的边界信息
重传
分组重传最大值为可发送数据最大值$\star$
加权平均往返时间RTTS:$\text{new}RTT_S=\left( 1-\alpha \right) \times \left( \text{old}RTT_S \right) +\alpha \times \left( \text{new}RTT \right) $
$0≤\alpha<1$:$\alpha\rightarrow0$ RTT值更新较慢;$\alpha\rightarrow1$RTT值更新较快。
推荐$\alpha=\dfrac18$
超时重传时间RTO:$RTO=RTT_S+4\times RTT_D$
$RTT_D$:RTT的偏差的加权平均值
$\text{new}RTT_D=\left{ \begin{array}{l}
RTT/2\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ D=1\
\left( 1-\beta \right) \times \text{old}RTT_D+\beta \times |RTT_S-\text{new}RTT|\ \ D\ne 1\
\end{array} \right. $$\beta<1$,推荐$\beta=\dfrac14$
Karn算法:$\text{new}RTO=\gamma \times(\text{old}RTO)$
- 推荐$\gamma=2$
失序
直接丢弃:引起被丢弃报文的重复传送,增加对网络带宽的消耗,但由于不用将该报文段暂存,可避免对接收方缓冲区的占用
失序报文暂存缓冲区:可以标面发送方已被接收方收到的失序报文重传,减少对网络带宽的消耗,增加了接收方缓冲区的开销
TCP 的流量控制
利用滑动窗口实现流量控制
- 接收端向发送端发送自己的接收窗口大小rwnd
- 若rwnd传输中丢失,则互相等待死锁
- 设置持续计时器:当TCP连接的一方收到对方零窗口通知,就启动该计时器;若持续计时器设置时间到期,就发送一个零窗口探测报文段(仅携带1字节的数据),而对方在确认报文段时给出窗口值
TCP的传输效率
Nagle算法:
- 若发送应用进程把要发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。
- 当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段发送出去,同时继续对随后到达的数据进行缓存。
- 只有在收到对前一个报文段的确认后才继续发送下一个报文段。
- 当到达的数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段
糊涂窗口综合症
每次仅发送一个字节或很少字节数据时,有效数据传输效率变得很低各层首部>>数据
原因:接收方应用进程消耗数据太慢
解决方法:让接收方等待一段时间,使得或者接收缓存已有足够空间容纳一个最长的报文段,或者等到接收缓存已有一半空闲的空间。只要出现这两种情况之一,接收方就发出确认报文,并向发送方通知当前的窗口大小。
TCP的拥塞控制
拥塞:在某段时间,$\sum 对资源需求 > 可用资源$对网络性能的评价
拥塞窗口:cwnd
TCP采用基于窗口的方法进行拥塞控制。该方法属于闭环控制方法
真正发送窗口值$=\min(接收方窗口值,拥塞窗口值)$
拥塞控制 & 流量控制
拥塞控制 | 流量控制 |
---|---|
防止过多的数据注入到网络中,使网络中的路由器或链路不致过载; | 抑制发送端发送数据的速率,以使接收端来得及接收; |
是一个全局性的过程,涉及到与降低网络传输性能有关的所有因素。 | 是点对点通信量的控制,是端到端的问题; |
TCP拥塞控制算法
慢开始
目的:用来确定网络的负载能力或拥塞程度。
算法的思路:由小到大逐渐增大拥塞窗口数值。
慢开始门限:防止拥塞窗口增长过大引起网络拥塞
慢:cwnd开始只发送一个报文段,用以试探网络的拥塞情况
操作:
- 先令拥塞窗口cwnd=1,即一个最大报文段长度MSS
- 每收到一个新报文段确认后,将cwnd加倍
- 即每经过一个传输轮次RTT,cwnd就会加倍
- 达到设置的慢开始门限状态变量ssthresh
- 当cwnd < ssthresh时,使用慢开始算法
- 当cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法
- 当cwnd = ssthresh时,既可使用慢开始算法,也可使用拥塞避免算法
拥塞避免
思路::让拥塞窗cwnd缓慢地增大,避免出现拥塞
操作:
- 每经过一个传输轮次,cwnd = cwnd + 1
- 当网络出现拥塞时
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(重传定时器超时):
1. ssthresh = max (cwnd/2,2)
2. cwnd = 1
3. 执行慢开始算法
快重传
目的:让发送方尽早知道发生了个别报文段的丢失
操作:接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认
重传时机:
- 失序立即发出对已收到报文段的重复确认
- 一旦收到3个连续的重复确认,立即重传
快恢复
原因:当发送端收到连续三个重复的确认时,认为网络很可能没有发生拥塞,因此现在不执行慢开始算法
算法操作:
- 慢开始门限ssthresh =当前拥塞窗口cwnd / 2
- 新拥塞窗**cwnd =慢开始门限ssthresh **
- 开始执行拥塞避免算法,使拥塞窗口缓慢地线性增大
发送窗口的上限值$=\min(rwnd, cwnd)$
主动队列管理AQM
- 所谓主动就是不要等到路由器的队列长度已经达到最大值时才不得不丢弃后面到达的分组,而是在队列长度达到某个值得警惕的数值时(即当网络拥塞有了某些拥塞征兆时),就主动丢弃到达的分组。
- AQM可以有不同实现方法,其中曾流行多年的就是随机早期检测RED (Random Early Detection)。
随机早期检测RED
- 使路由器的队列维持两个参数:队列长度最小门限$TH_{min}$和最大门限$Th_{max}$
- RED对每一个到达的分组都先计算平均队列长度$L_{AV}$。
- 若平均队列长度小于最小门限$TH_{min}$,则将新到达的分组放入队
列进行排队。 - 若平均队列长度超过最大门限$Th_{max}$ ,则将新到达的分组丢弃。
- 若平均队列长度在最小门限$TH_{min}$和最大门限$Th_{max}$之间,则按照某一概率p将新到达的分组丢弃。
- 若平均队列长度小于最小门限$TH_{min}$,则将新到达的分组放入队