计算机网络 - 运输层

参考资料

运输层概述

本系列之前的课程所介绍的计算机网络体系结构中的物理层、数据链路层以及网络层之间他们共同解决了将主机通过异构网络互连起来所面临的问题,实现了主机到主机之间的通信

但是实际上在计算机网络中进行通信的真正实体是位于通信两端的主机中的进程

因此运输层协议的功能就出现了:

  • 如何为运行在不同主机上的应用进程提供直接的通信服务?
  • 运输层协议又被称为端到端协议。

网络层和运输层的作用范围如下:

1

运输层简单传输过程:

2

首先先明确逻辑通信的概念:

“逻辑通信”是指运输层之间的通信使人感觉是沿水平方向传送数据,但事实上,这两条数据并没有一条水平方向的物理连接,要传送的数据是沿着图中上下多次的虚线方向传送

假设进程Ap1与Ap4之间进行基于网络的通信,他们通信的简单过程如下:

  1. 根据不同的进程,在运输层选择使用不同的端口

  2. 通过网络层及其下层来传输应用层报文

  3. 将收到的应用层报文到达接收方的运输层后,通过不同的端口,交付给应用层中相应的应用进程

根据应用需求的不同,因特网的运输层为应用层提供了两种不同的运输协议,即面向连接的TCP和无连接的UDP

运输层端口号、复用和分用的概念

端口号

首先明白为什么要用到端口号:

  • 在操作系统中 ,运行在计算机上的进程使用进程标识符PID来标志,但是因特网上的计算机并不是使用统一的操作系统,不同的操作系统使用不同格式的进程标识符。
  • 为了使运行不同系统的计算机的应用进程之间能够进行网络通信,就必须使用统一的方法来对TCP/IP体系的应用进程进行标识。也就是使用端口号。
  • TCP/IP体系的运输层使用端口号来区分应用层的不同应用进程。

3

发送方的复用和接收方的分用

  • 复用可以理解为多个进程重复使用一个协议进行应用报文的封装
  • 分用可以理解为一个封装好的应用报文根据某协议进行解析成不同的进程应用报文

例如:

4

在发送方中,多个进程通过端口利用一个运输层协议将数据封装成报文后发送,这就称为发送方复用,不同协议就叫不同协议复用,如图中的UDP复用。

在IP复用中也会根据协议字段的不同将其使用不同协议再次进行封装。

在接收方中,利用一个协议,将用报文解析成不同数据,将数据根据端口发送不同进程,这就称为接收方分用。

在IP分用中也会根据协议字段的不同将其使用不同协议进行解析。
1
2
3
4
5
6
7

在TCP/IP体系的应用层常用协议的运输层熟知端口号:

5

UDP和TCP的对比

  • 用户数据报协议UDP(User Datagram Protocol)、传输控制协议TCP(Transmission Control Protocol)

  • UDP和TCP是TCP/IP体系结构运输层中的两个重要协议,其使用频率仅次于网际层的IP协议。

6

  • 运输层采用面向连接的 TCP 协议时,尽管下面的网络是不可靠的(只提供尽最大努力服务),但TCP协议就相当于在逻辑上建立了一条通信信道,该信道是全双工的可靠信道

  • 当运输层采用无连接的 UDP 协议时,这种逻辑通信信道是一条不可靠信道

接下来,我们从以下几个方面对比UDP和TCP:

  1. 在连接方式上:
  • UDP是无连接的通信方式
  • TCP是通过著名的三次握手 建立连接,四次挥手释放连接

7

  1. 在传播方式上:

8

  1. 在报文传输处理上:

9

UDP协议中,对于应用层传输下来的报文不进行处理,保留报文的边界。在给报文加上UDP首部,进行发送。UDP接收方首部接收到UDP数据后,去除其首部,交付给应用层。可以看出,UDP是针对报文为单位进行处理的,也就是UDP是面向应用报文的。

在TCP协议中比较复杂:

  • 在TCP发送方:

    • TCP协议会把应用进程交付下来的数据块(报文)看作是一连串无结构的字节流(TCP并不知道这些子节含义),将他们编号,并存储在自己的发送缓存中,TCP再根据发送策略,提取一定量的字节,加上TCP首部,构建成TCP报文进行发送。
  • 对于接收方,同时进行两件事: -从所接受到的TCP报文段中,取出数据载荷部分并存储在接收缓存中,同时将接收缓存中的一些字节交付给应用进程

有两个点值得注意:

  1. TCP协议保证接收方收到的字节流和发送方应用进程发出的字节流完全一样。
  2. TCP不保证接收方应用进程所收到的数据块与发送方发送的数据块,具有对应大小的关系,例如,发送方应用进程交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块,就把收到的字节流交付给了上层的应用进程。但就是不会全部将数据交付给上层。

因此接收方的TCP应用进程必须有能力识别收到的字节流,把它还原成有意义的应用层数据。

可以看出,TCP对报文的处理是以子节为单位的,也就是TCP是面向字节流的,这正是TCP实现可靠传输、流量控制、以及拥塞控制的基础

  1. 在给上层提供的服务上:

10

  • UDP提供的是不可靠服务:

    • 对于发送的UDP数据报,接收方在检测到其误码后直接丢弃,不做其他操作。对于发送方发送过程中出现分组丢失,也不做处理。因此其传输数据是不一定能使接收方全部收到数据,因此是不可靠服务
  • TCP提供的是可靠服务:

    • 由于TCP字传输过程中需要建立连接,通过建立的可靠信道进行传输,因此不会出现传输差错,也就是误码、丢失、乱序、重复。因此可以保证发送端发送什么,接收端接收到什么,是可靠传输。
  1. 在协议首部的对比上:

11

  • 由于UDP不提供可靠传输的服务,因此其首部只需要在网际层的基础上添加区分端口的子节,其首部比较简单。
  • 在TCP中,需要提供可靠传输、流量控制、拥塞控制等服务,首部比较复杂,字段比较多。

TCP和UDP的对比总结:

12

TCP的流量控制

  • 拥塞指的是某段时间内,若对网络中的某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏。
  • 在计算机网络种的资源包括链路容量(带宽)、交换节点种的缓存和处理机等。
  • 若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降
  • 可以将拥塞形象的理解为堵车

13

拥塞控制:全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。

TCP拥塞控制的4种算法:

  1. 慢开始;
  2. 拥塞避免;
  3. 快重传;
  4. 快恢复。

慢开始:TCP开始发送报文段时,先设置拥塞窗口cwnd=1 ,然后每经过一个传输轮次,拥塞窗口就加倍。为了防止拥塞窗口cwnd增长过快,还需要设置一个慢开始门限ssthresh。

  • 当 cwnd < ssthresh 时,使用慢开始算法;
  • 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法;
  • 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。

拥塞避免:让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd+1,而不是像慢开始阶段那样加倍增长。

快重传:在出现分组错误后,发送方尽快重传数据,而不是等待超时计时器超时再重传。

快重传算法三个原则:

  1. 要求接收方不要等等自己发送数据时才进行捎带确认,而是要立即发送确认
  2. 即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认
  3. 发送方一旦收到了3个连续的重复确认,就立即将相应的报文段立即重传,不用等到超时计时器超时后再重传。

快恢复:

  • 发送方在收到3个重复确认后,就知道现在只是丢失了个别的报文段。于是不开始启动慢开始算法,转而执行快恢复算法。
  • 快恢复算法是发送方将慢开始门限ssthresh值和拥塞窗口cwnd值调整为当前窗口的一半,并开始使用拥塞避免算法
  • 有部分快恢复实现是把快回复开始时的拥塞窗口swnd值再增大一些,即等于SSTHRESH + 3。

四个算法再传输过程中的使用顺序图:

14

TCP超时重传时间的选择是TCP最复杂的问题之一

TCP的运输连接管理

TCP的连接建立要解决以下三个问题

  1. 使TCP双方都能确知对方的存在。
  2. 使TCP双方能够协商一些参数(如窗口最大值、是否使用窗口扩大选项和时间戳选项和服务质量等等)。
  3. 使TCP双方能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。

使用三报文握手建立连接的具体过程:

15

这里有一个问题:

为什么TCP客户端进行最后还要发送一个普通的TCP确认报文段呢?,是否多余?

答案是否定的。

三次握手建立连接是为了防止已经失效的连接请求报文段突然又传到服务端,产生错误

例如,下面采用两次握手就建立连接:

16

使用四报文挥手释放连接的具体过程:

17

此时就会出现一个问题:

为什么客户端不发送报文段后直接关闭,而是要等待2MSL个时间后才关闭?,是否有必要?

答案是有必要

考虑以下情况:

18

若客户端发送完最后一次报文后,也就是第四次挥手后就直接进入关闭状态,此时若第四次挥手报文丢失,会导致服务器的超时重传

此时客户端又已经关闭,导致不接受该报文,因此服务器会一直不断重传,并一直处于最后确认状态无法进入关闭状态

因此,有以下结论: 客户端进入时间等待状态以及处于该状态2MSL时长,可以确保TCP服务器进程可以收到最后一个TCP确认报文段而进入关闭状态

TCP客户进程在发送完最后一个TCP确认报文段后,在经过2MSL时长,就可以使本次连接持续时间内所产生的所有报文段都从网络中消失,这样就可以使使下一个新的TCP连接中,不会出现旧连接中的报文段

若出现这样一种情况:

TCP双方已经建立了连接,但是传输过程中TCP客户进程所在的主机出现了故障,此时TCP服务器进程以后就不能再收到TCP客户进程发来的数据,这时服务器进程会一直处于等待状态。

为了使TCP服务器进程不要再白白等待下去出现了TCP保活计时器:

TCP保活计时器:

19

TCP报文的首部格式

为了实现可靠传输,TCP采用了面向字节流的方式。

  • 在发送数据时,从发送缓存中取出一部分或者全部字节,并给其添加一个首部使之称为TCP报文段。

19

  • 源端口:占2个字节,写入源端口号,用来标识发送该TCP报文段的应用程序。

  • 目的端口:占2个字节,写入目的端口号,用来标识接收该TCP报文段的应用程序。

  • 序号:4字节。0~2^31-1,指的是本报文段所发送的数据的第一个字节的序号。比如本次发送的报文从301开始,报文长度是100字节,那么下次发送的报文段序号应该就是401。

  • 确认号:4字节。确认到该字节为止之前的报文都正确接收了。确认号=N,那么表明到N-1为止的所有数据都已正确接收。

  • 数据偏移:4位,因为有长度不定的选项字节段,因此用数据偏移来表示TCP报文段的数据从哪里开始。前面从源端口到紧急指针是固定的20个字节,数据偏移共有4位,能表达最大的数是15,数据偏移的单位是32位,也就是4字节,因此,tcp首部长度不能超过15*4=60字节,也是意味着选项的长度不能超过40字节。(即该字段实际上指出了TCP报文段的首部长度)

  • 保留:占6位,为今后使用,目前置为0.

  • 紧急URG:URG=1时,说明这个报文段是紧急数据,你应该立即上传给应用层,比如中断命令等。

  • 确认ACK:ACK=1时,是TCP建立阶段用,以及在连接简历后所有报文段都置1。

  • 推送PSH:PSH=1时,需要快速响应的报文,接收方不等缓存填满,直接把目前的缓存都推送上去。

  • 复位RST:RST=1时,表明TCP连接出现严重差错,必须释放连接,然后重新建立连接。

  • 同步SYN:建立连接时用,SYN=1,ACK=0时,代表建立连接报文段,对方的响应是SYN=1,ACK=1。因此SYN=1时就代表这是一个请求连接或连接接受报文。

  • 终止FIN:用来释放连接,FIN置1时,就代表要求释放运输连接。

  • 窗口:2字节,指的是发送该报文段的接收窗口还能接受多少,告诉对方,你还能发送多少。这个是根据缓存大小和缓存内已存储的数据大小决定的

  • 校验和:2字节。检查范围包括TCP报文段的首部和数据载荷两部分。在计算校验和时,要在TCP报文段的前面加上12字节的伪首部。

  • 紧急指针:2字节,配合URG使用,URG置1时,它指出本报文段中的紧急数据的长度。当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立刻封装到一个TCP报文段中进行发送。紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据。

  • 选项:长度可变,最大40字节。包括最大报文段长度MSS选项、窗口扩大选项、时间戳选项、选择确认选项。

  • 填充:由于选项的长度可变,因此使用填充来确保报文段首部能被4整除。