运输层的主要任务
· 我们上一章学习的网络层提供的IP协议用于建立主机之间的逻辑连接,但是,IP数据报并不知道它封装的数据是用来干什么的,它只管传输。
· 而运输层就是要解决这个问题,从运输层的角度来看,通信的真正端点并不是主机,而是主机中的进程。即端到端的通信其实是应用进程之间的通信。
· 所以运输层实际上是为应用程序进程之间建立逻辑连接,通过端口和套接字(Socket)识别进程,通过TCP或UDP协议实现进程间通信。
运输层协议概述
进程之间通信
· 运输层的地位非常重要,它起到一个承上启下的作用,对于面向通信部分来说,它是最高层;对于面向用户部分来说,它是最底层。
· 只有边缘部分的主机的协议栈才会有运输层,路由器、交换机等设备都没有运输层。
· 网络层和运输层的区别:
网络层是为主机之间提供逻辑通信。
运输层是为应用程序进程之间提供端到端的逻辑通信。
· 运输层向高层用户屏蔽了下面网络核心的细节:
运输层的端口
· 我们知道,操作系统使用进程ID(PID)来标识一台计算机上的每一个进程。而现在运输层需要连接的两个进程在两台不同的主机上,为了唯一地标识两台主机上的进程,我们引入端口(Port)的概念。
· 注意区分:
路由器或交换机上的端口是硬件端口,硬件端口是不同硬件设备进行交互的端口。
运输层引入的是软件端口,用于不同主机上的进程的通信。
· 运输层的端口具有本地含义:两台主机上相同的端口是没有关联的。
两台主机上的80端口没有关联,可能左边主机80端口运行着HTTP服务,右边主机80端口运行着某个JavaWeb服务。
· 就像网络层中IP协议使用"协议类型"首部字段实现多种协议的复用一样,运输层就是通过端口号去实现TCP或UDP的复用:
· 运输层端口类别:
· 常用的熟知端口号,最好记下来:
运输层的2个主要协议
· 用户数据报协议(User Datagram Protocol,UDP)
· 传输控制协议(Transmission Control Protocol,TCP)
· 为什么需要两种协议?因为要满足应用层不同的需要。
· 典型应用举例如下,一般可靠性要求比较高的会选择TCP,否则UDP:
用户数据报协议UDP
· UDP其实只在IP数据报的基础上增加了很少一点的功能:
通过端口号实现应用进程的复用和分用。
对UDP数据报实现差错检测。
· UDP的协议栈也很简单,直接把应用层的报文封装到UDP报文里去即可:
· UDP协议的报文是不会进行分片的,一次发送一整个报文,至于在传输过程超过MTU则交给网络层的IP数据报进行分片:
· UDP是面向报文的:
发送方的应用层无论交给UDP多长的报文,UDP既不合并,也不拆分,一次性发送一整个报文。
同理,接收方接收到一个UDP报文后,去除UDP首部后就直接把数据交给上层应用层,一次性交付一整个完整报文。
因此应用程序必须选择合适的报文大小:
- UDP报文太长:IP层传输时会分片,降低IP层的效率。
- UDP报文太短:IP数据报的首部相对长度太大,降低IP层效率。
· UDP的主要特点:
无连接:发送数据之前不需要建立逻辑连接,因此减少了开销和发送数据之前的时延。
尽最大努力交付:UDP不保证可靠交付,因此主机不需要维持复杂的连接状态表。
面向报文:前面已经提过,UDP对应用层报文不拆分或合并,一次性完整交付。
没有拥塞控制:若网络出现拥塞,UDP也不会降低发送速率,因此很适合多媒体通信。
支持一对一、一对多、多对一、多对多的交互通信。
首部开销很小:只有8个字节,TCP首部需要20个字节。
UDP的首部格式
· UDP首部有8个字节,由4个字段组成,每个字段2个字节
其中的长度指的是UDP数据报的长度,包括首部+数据。
· 在计算校验和时,会临时把12字节的伪首部和UDP数据报连接在一起,伪首部仅仅为了计算校验和,检验有错就丢弃:
· IP和UDP校验和比较:
二者都是按照16位二进制反码规则求和,结果再反码。
二者校验范围不同:IP只校验IP首部,UDP校验伪首部+UDP首部+数据。
传输控制协议TCP
· TCP是在无连接、不可靠的IP网络服务基础之上提供面向连接、可靠交付的服务。
· TCP的主要特点:
面向连接:每一条TCP只能有两个端点,每一条TCP只能是点对点的(一对一)。
提供可靠交付的服务:通过确认、重传等机制保证无差错、不丢失、不重复传送、按顺序。
全双工通信:通信双方都设有接收和发送缓存。发送时,应用程序把数据放入发送缓存,TCP读取缓存中的字节发送;接收时,TCP把字节流写入接收缓存,应用程序从中读取。
面向字节流:TCP中的流(Stream)指的是流入或流出进程的字节序列。TCP把应用程序交下来的数据看成是一串无结构的字节流。
· TCP的面向字节流:
TCP不关心应用程序往发送缓存里面写入多少字节,它会对连续的字节流进行分段,形成TCP报文段进行发送。
PS:每个协议的数据单位名称不同:以太网-帧,IP-数据报/分组,UDP-数据报,TCP-报文段。
那TCP字节流的大小如何确定呢?要由接收方和发送方进行协商。TCP可根据接收方的窗口值(接收方在接收缓存里开辟的空间大小)和当前网络拥塞程度来控制发送的字节流大小。
TCP可以把太长的数据块分段进行发送,也可以等待累积足够多的短字节后再发送。
TCP的连接
· TCP连接是一条虚连接而不是一条真正的物理连接。
· 每一条TCP连接有2个端点。
· TCP是基于套接字(Socket)建立起来的,套接字由IP地址和端口组成。
· 每一条TCP连接唯一地被通信两端的两个套接字所确定。
可靠传输的工作原理
·理想的传输条件有以下2个特点:
传输信道不产生差错。
不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据。
· 因此,理想的传输条件下不需要采取任何措施就可以保证可靠传输,但实际的网络是两个条件都不具备,所以我们必须使用一些可靠传输协议来保证可靠传输。
停止等待协议
· 核心思想——确认和重传机制:
每发送完一个分组(注意不是IP层的分组,是TCP分段的数据单位)就停止发送,等待接收方的确认。
在收到确认后再发送下一个分组。
每个发送分组和确认分组都需要编号。
设置超时重传计时。
· 正常无差错的情况:A发完M1,等待B的确认(ACK);B收到M1向A发送ACK1;A收到ACK1,再向B发送下一个分组M2。
· 出现差错1——发送时出错:
B在接收到M1后检测到M1出现差错。
M1在传输过程中丢失了。
- 如果在这两种情况下,B都不会发送任何消息,A如何知道B是否正确接收M1?如果A知道B没有正确接收,为了保证可靠通信,A必须重发分组,何时重发?
- 使用超时重传:每一个已发送的分组都设置了一个超时计时器。A在发送M1的时候会启动计时器,如果超过设置的最大等待时间t_out,则认为发送或接收出现问题,进行超时重发。
· 出现差错2——回复时出错:分组M1正确到达B,但是B回送的ACK1确认丢失或确认延迟了,那么A会超时重传,此时B再次收到重复的M1,那么B如何知道收到了重复的分组并丢弃?
- 确认丢失:B对于M1的回复ACK1丢失了之后,A会超时重发M1,这时B应该丢弃重复的M1不向上级交付,并重新发送确认ACK1。
- 确认延迟:虽然传输过程没出错,但是B给M1的确认ACK1迟到了,A超时重发,B丢弃重复的M1并重传ACK1,A收到ACK1继续发送M2,此时A收到了迟到的ACK1,是重复的,因此A应该丢弃重复的ACK1。
· 自动重传请求(Automatic Repeat reQuest,ARQ):指的是重传的请求是自动进行的,接收方不需要请求发送方重传某个错误的分组。
· 信道利用率:虽然停止等待协议实现起来非常简单,但是它的缺点就是信道利用率太低:
可以发现,当RTT>>T_D时,信道的利用率就会变得非常低,此时若出现重传,那利用率就会更低。
· 流水线传输:为了提高传输效率,我们要在信道上不间断地传送,不必等待接收到确认后再发送下一个分组
但是,尽管发送方一股脑全发出去了,接收方不一定有能力进行接收和处理,因此我们需要控制流水线传输一次性发送的分组数量。
连续ARQ协议
· 发送方可以一次连续发送多少个分组?
使用滑动窗口协议控制发送方和接收方所能发送和接收的分组数量和编号。
每收到一个确认,发送方就把窗口向后滑动。
· 接收方什么时候确认?
采用累积确认的方式:即并非一个个分组确认,而是对按序到达的最后一个分组进行确认。
采用回退N(Go-Back N)方法进行重传。
· 发送方维护一个发送窗口,只有位于窗口内的分组可以连续发送;收到确认后,就把滑动窗口向后移动一个分组:
· 累积确认:ACK1是普通确认,表示M0确认并请求M1;ACK2也是普通确认,表示M1收到并请求M2;ACK5是累积确认,表示M5、M4、M3、M2都确认。
· 回退N重传:表示需要再退回来重传已发送过的N个分组
可见,当线路质量不好的时候,连续ARQ协议会带来负面影响。