Skip to content

运输层

运输层是整个网络体系结构中的关键层级之一。一定要弄清以下一些重要概念:

(1) 运输层为相互通信的应用进程提供逻辑通信
(2) 端口和套接字的意义
(3) 无连接的 UDP 的特点
(4) 面向连接的 TCP 的特点
(5) 在不可靠的网络上实现可靠传输的工作远离,停止等待协议和 ARQ 协议
(6) TCP 的滑动窗口、流量控制、拥塞控制和连接管理

运输层协议概述

进程之间的通信

从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。
当网络的边缘部分中的两台主机使用网络的核心部分的功能进行端到端的通信时,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时只用到下三层的功能。

通过下图来说明运输层的作用。
设局域网 LAN1 上的主机 A 和局域网 LAN2 上的主机 B 通过互连的广域网 WAN 进行通信。
我们知道,IP 协议能够把源主机 A 发送出的分组,按照首部中的目的地址,送交到目的主机 B,那么,为什么还需要运输层呢?

运输层提供了逻辑通信

从 IP 层来说,通信的两端是两台主机。IP 数据报的首部明确地标志了这两台主机的 IP 地址。但“两台主机之间的通信”这种说法还不够清楚。
这是因为,真正进行通信的实体是在主机中的进程,是这台主机中的一个进程和另一台主机中的一个进程在交换数据(即通信)。
因此严格地讲,两台主机进行通信就是两台主机中的应用进程互相通信。
IP 协议虽然能把分组送到目的主机,但是这个分组还停留在主机的网络层而没有交付主机中的应用进程。
从运输层的角度看,通信的真正端点并不是主机中的进程。也就是说,端到端的通信是应用进程之间的通信。
在一台主机中经常有多个应用进程同时分别和另一台主机中的多个应用进程通信。
例如,某用户在使用浏览器查找某网站的信息时,其主机的应用层运行浏览器客户进程。
如果在浏览网页的同时,还要用电子邮件给网站发送反馈一间,那么主机的应用层就还要运行电子邮件的客户进程。

在上图中,主机 A 的应用进程 AP1 和 主机 B 的应用进程 AP3 通信,而与此同时,应用进程 AP2 也和对方的应用进程 AP4 通信。
这表明运输层有一个很重要的功能--复用分用
这里的“复用”是指在发送方不同的应用进程都可以使用同一个运输层协议传送数据(当然需要加上适当的首部),而“分用”是指接收方的运输层在剥去报文的首部后能够把这些数据正确交付目的应用进程。
图中两个运输层之间有一个双向箭头,写明“运输层提供应用进程间的逻辑通信”。
“逻辑通信”的意思是:从应用层来看,只要把应用层报文交给下面的圆弧层,运输层就可以把这报文传送到对方的运输层(哪怕双方相距很远,例如几千公里),好像这种通信就是沿水平方向直接传送数据。
但事实上这两个运输层之间并没有一条水平方向的物理连接。
数据的传送是沿着图中的虚线方向(经过多个层次)传送的。“逻辑通信”的意思是“好像是这样通信的,但事实上并非真的这样通信”

从这里可以看出网络层和运输层有明显的区别。
网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信(见下图)。
然而正如后面还要讨论的,运输层还具有网络层无法代替的许多其他重要功能。

运输层协议和网络层协议的主要区别

运输层还要对收到的报文进行差错检测。
在网络层,IP 数据报首部中的检验和字段,只检验首部是否出现差错而不检查数据部分。

根据应用程序的不同需求,运输层需要有两种不同的运输协议,即面向连接的 TCP 和无连接的 UDP。

还应指出,运输层向高层用户屏蔽了下面网络核心的细节(如网络拓扑、所采用的路由选择协议等),它使应用进程看见的就是好像在两个运输层实体之间有一条端到端的逻辑通信信道,但这条逻辑通信信道对上层的表现却因运输层使用的不同协议而有很大的差别。
当运输层采用面向连接的 TCP 协议时,尽管下面的网络是不可靠的(只提供尽量最大努力服务),但这种逻辑通信信道就相当于一条全双工的可靠信道。
但当运输层采用无连接的 UDP 协议时,这种逻辑通信信道仍然是一条不可靠信道。

运输层的两个主要协议

TCP/IP 运输层的两个主要协议都是互联网的正是标准,即:

(1) 用户数据报协议 UDP(User Datagram Protocol)[RFC 768]
(2) 传输控制协议 TCP(Transmission Control Protocol)[RFC 793]

下图给出了这两种协议在协议栈中的位置

TCPIP体系中的运输层协议

按照 OSI 的术语,两个对等运输实体在通信时传送的数据单位叫做运输协议数据但愿 TPDU。
但在 TCP/IP 体系中,则根据所使用的协议时 TCP 或 UDP,分别称之为 TCP 报文段或 UPD 用户数据报

UDP 在传送数据之前不需要先建立连接。
远地主机的运输层在收到 UDP 报文后,不需要给出任何确认。
虽然 UDP 不提供可靠交付,但在某些情况下 UDP 却是一种最有效的工作方式。

TCP 则提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。
TCP 不提供广播或多播服务。由于 TCP 要提供可靠的、面向连接的运输服务,因此不可避免地增加了许多的开销,如确认、流量控制、计时器以及连接管理等。
这不仅使协议数据单元的首部增大很多,还要占用许多的处理机资源。

下表给出了一些应用和应用层协议主要使用的运输层协议(UDP 或 TCP)

应用 应用层协议 运输层协议
名字转换 DNS(域名系统) UDP
文件传送 TFTP(简单文件传送协议) UDP
路由选择协议 RIP(路由信息协议) UDP
IP 地址配置 DHCP(动态主机配置协议) UDP
网络管理 SNMP(简单网络管理协议) UDP
远程文件服务器 NFS(网络文件系统) UDP
IP 电话 专用协议 UDP
流式多媒体通信 专用协议 UDP
多播 IGMP(网际组管理协议) UDP
电子邮件 SMTP(简单邮件传送协议) TCP
远程终端接入 TELNET(远程终端协议) TCP
万维网 HTTP(超文本传送协议) TCP
文件传送 FTP(文件传送协议) TCP

运输层的端口

前面已经提到过运输层的复用和分用功能。其实在日常生活中也有很多复用和分用的例子。
假定一个机构的所有部门向外单位发出的公文都由收发室负责寄出,这相当于各部门都“复用”这个收发室。
当收发室收到从外单位寄来的公文时,则要完成“分用”功能,即按照信封上写明的本机构的部门地址把公文正确进行交付。

运输层的复用和分用功能也是类似的。
应用层所有的应用进程都可以通过运输层再再传送到 IP层(网络层),这就是复用
运输层从 IP 层收到发送给各应用进程的数据后,必须分别交付指明的各应用进程,这就是分用
显然,给应用层的每个应用进程赋予一个非常明确的标志是至关重要。

我们知道,在单个计算机中的进程是用进程标识符(一个不大的整数)来标志的。
但是在互联网环境下,用计算机操作系统所指派的这种进程标识符来标志运行在应用层的各种引用进程则是不行的。
这是因为在互联网上使用的计算机的操作系统种类很多,而不同的操作系统又使用不同格式的进程标识符。
为了使运行不同操作系统的计算机的应用进程能够相互通信,就必须用统一的方法(而这种方法必须与特定操作系统无关)对 TCP/IP 体系的应用进程进行标志

但是,把一个特定机器上运行的特定进程,指明为互联网上通信的最后终点还是不可行的。
这是因为进程的创建和撤销都是动态的,通信的一方几乎无法识别对方机器上的进程。
另外,我们往往需要利用目的主机提供的功能来识别终点,而不需要知道具体实现这个功能的进程是哪一个(例如,要和互联网上的某个邮件服务器联系,并不一定要知道这个服务器功能是由目的主机上的哪个进程实现的)

解决这个问题的方法就是在运输层使用协议端口号(protocol port number),或通常简称为端口(port)。
这就是说,虽然通信的终点是应用进程,但只要把所传送的报文交到目的主机的某个合适的目的端口,剩下等工作(即最后交付目的进程)就由 TCP 或 UDP 来完成。

请注意,这种在协议栈层间的抽象的协议端口是软件端口,和路由器或交换机上的硬件端口是完全不同的概念。
硬件端口是不同硬件设备进行交互的接口,而软件端口是应用层的各种协议进程与运输实体进行层间交互的一种地址。
不同的系统具体实现端口的方法可以是不同的(取决于系统使用的操作系统)。

在后面将讲到的 UDP 和 TCP 的首部格式中,我们将会看到它们都有源端口和目的端口这两个重要字段。
当运输层收到 IP 层交上来的运输层报文时,就能够根据其首部中的目的端口号把数据交付应用层的应用进程。

TCP/IP 的运输层用一个 16 位端口号来标志一个端口。
但请注意,端口号只具有本地意义,它只是为了标志本计算机应用层中的各个进程在和运输层交互时的层间接口。
在互联网上不同计算机中,相同的端口号是没有关联的。
16 位的端口号可允许有 65535 个不同的端口号,这个数目对一个计算机来说是足够用的。

由此可见,两个计算机中的进程要相互通信,不仅必须知道对方的 IP 地址(为了找到对方的计算机),而且要知道对方的端口号(为了找到对方计算机中的应用进程)。这和我们寄信的过程类似。
当我们要给某人写信时,就必须在信封上写明他的通信地址(这是为了找到他的住处,相当于 IP 地址),并且还要写上收件人的姓名(这是因为在同一住所中可能有好几个人,这相当于端口号)。
在信封上还写明自己的地址。当收信人回信时,很容易在信封上找到发信人的地址。互联网上的计算机通信是采用客户-服务器方式。
客户在发起通信请求时,必须先知道对方服务器的 IP 地址的端口号。因此运输层的端口号分为下面的两大类。

(1) 服务器端使用的端口号这里又分为两类,最重要的一类叫做熟知端口号系统端口号,数值为 0 到 1023。
这些数值可在网址 www.iana.org 查到。IANA 把这些端口号指派给了 TCP/IP 最重要的一些应用程序,让所有的用户都知道。
当一种新的应用程序出现后,IANA 必须为它指派一个熟知端口,否则互联网上的其他应用进程就无法和它进行通信。

下面给出了一些常用的熟知端口号

  • FTP: 21
  • TELENT: 23
  • SMTP: 25
  • DNS: 53
  • TFTP: 69
  • HTTP: 80
  • SNMP: 161
  • SNMP(trap): 162
  • HTTPS: 443

另一类叫做登记端口号,数值为 1024 到 49151。这类端口号是为没有熟知端口号的应用程序使用的。
使用这类端口号必须在 IANA 按照规定的手续登记,以防止重复。

(2) 客户端使用的端口号数值为 49152 到 65535。
由于这类端口号仅在客户进程运行时才动态选择,因此又叫短暂端口号
这类端口号留给客户进程的报文时,就知道了客户进程所使用的端口号,因而可以把数据发送给客户进程。
通信结束后,刚才已使用过的客户端口号就不复存在,这个端口号就可以供其他客户进程使用。

用户数据报协议 UDP

UDP 概述

用户数据报协议 UDP 只在 IP 的数据报服务上增加了很少一点的功能,这就是复用和分用的功能以及差错检测的功能。UDP 的主要特点是:

(1) UDP 是无连接的,即发送数据之前不需要建立连接(当然,发送数据结束时也没有连接可释放),因此减少了开销和发送数据之前的时延
(2) UDP 使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表(这里面有许多参数)
(3) UDP 是面向报文的。发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,即不合并,也不拆分,而是保留这些报文的边界。
这就是说,应用层交给 UDP 多长的报文,UDP 就照样发送,即一次发送一个报文,如图所示:

UDP是面向报文的

在接收方的 UDP,对 IP 层交上来的 UDP 的 UDP 数据报,在去除首部后就原封不懂地交付上层的应用进程。也就是说,UDP 一次交付一个完整的报文。
因此,应用程序必须选择合适大小的报文。若报文太长,UDP 把它交给 IP 层后,IP 层在传送时可能要进行分片,这会降低 IP 层的效率。
反之,若报文太短,UDP 把它交给 IP 层后,会使 IP 数据报的首部的相对长度太大,这也降低了 IP 层的效率

(4) UDP 没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率较低。这对某些实时应用是很重要的。
很多的实时应用(如 IP 电话、实时视频会议等)要求源主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但却不允许数据有太大的时延。UDP 正好适合这种要求

(5) UDP 支持一对一、一对多、多对一和多对多的交互通信
(6) UDP 的首部开销小,只有 8 个字节,比 TCP 的 20 个字节的首部要短

虽然某些实时应用需要使用没有拥塞控制的 UDP,但当很多的源主机同时都向网络发送高速率的实时视频流时,网络就有可能发生拥塞,结果大家都无法正常接收。
因此,不使用拥塞控制功能的 UDP 有可能会引起网络产生严重的拥塞问题。

还有一些使用 UDP 的实时应用,需要对 UDP 的不可靠的传输进行适当的改进,以减少数据的丢失。
在这种情况下,应用进程本身可以在不影响应用的实时性的前提下,增加一些提高可靠性的措施,如采用前向纠错或重传已丢失的报文。

UDP 的首部格式

用户数据报 UDP 有两个字段:数据字段和首部字段。首部字段很简单,只有 8 个字节(如下图所示),由四个字段组成,每个字段的长度都是两个字节。各字段意义如下:

UDP用户数据报的首部和伪首部

(1) 源端口源端口号。在需要对方回信时需要。不需要时可用全为 0
(2) 目的端口目的端口号。这在终点交付报文时必须使用
(3) 长度 UDP 用户数据报的长度,其最小值时 8(仅有首部)
(4) 检验和检测 UDP 用户数据报在传输中是否有错。有错就丢弃

当运输层从 IP 收到 UDP 数据报时,就根据首部中的目的端口,把 UDP 数据报通过相应的端口,上交最后的终点--应用进程。
下图是 UDP 基于端口分用的示意图

UDP基于端口的分用

如果接收方 UDP 发现收到的报文中的目的端口号不正确(即不存在对应于该端口号的应用进程),就丢弃该报文,并由网际控制报文协议 ICMP 发送“端口不可达”差错报文给发送方。

请注意,虽然在 UDP 之间的通信要用到其端口号,但由于 UDP 的通信是无连接的,因此不需要使用套接字(TCP 之间的通信必须要在两个套接字之间建立连接)

UDP 用户数据报首部中检验和的计算方法有些特殊。
在计算检验和时,要在 UDP 用户数据报之前增加 12 子字节的伪首部。
所谓“伪首部”是因为这种伪首部并不是 UDP 用户数据报真正的首部。
只是在计算检验和时,临时添加在 UDP 用户数据报前面,得到一个临时的 UDP 用户数据报。检验和就是按照这个临时的 UDP 用户数据报来计算的。
伪首部既不向下传送也不向上递交,而仅仅是为了计算检验和。

传输控制协议 TCP 概述

TCP 最主要的特点

TCP 是 TCP/IP 体系中非常复杂的一个协议。下面介绍 TCP 最主要的特点。

(1) TCP 是面向连接的运输层协议。这就是说,应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。
在传送数据完毕后,必须释放已经建立的 TCP 连接。
也就是说,应用进程之间的通信好像在“打电话”:通话前要先拨号建立连接,通话结束后要挂机释放连接

(2) 每一条 TCP 连接只能有两个端点,每一条 TCP 连接只能是点对点的(一对一)。这个问题后面还要进一步讨论。

(3) TCP 提供可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达

(4) TCP 提供全双工通信。TCP 允许通信双方的应用进程在任何时候都能发送数据。
TCP 连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。
在发送时,应用程序在把数据传送给 TCP 的缓存后,就可以做自己的事,而 TCP 在合适的时候把数据发送出去。
在接收时,TCP 把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。

(5) 面向字节流。TCP 中的“流”(stream)指的是流入到进程或从进程流出的字节序列。
“面向字节流”的含义是:虽然应用程序和 TCP 的交互一次一个数据块(大小不等),但 TCP 把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。
TCP 并不知道所传送的字节流的含义。
TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小关系(例如,发送方应用程序交给发送方的 TCP 共 10 个数据块,但接收方的 TCP 可能只用了 4 个数据块就把收到的字节流交付上层的应用程序)。
但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。
当然,接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。

下图是上述概念的示意图:

TCP面向字节流的概念

为了突出示意图的要点,我们只画出了一个方向的数据流。
但请注意,在实际的网络中,一个 TCP 报文段包含成千个字节是很常见的,而图中的各部分都只画出了几个字节,这仅仅是为了更方便地说明”面向字节流“的概念。
另一点很重要的是:图中的 TCP 连接是一条虚连接(也就是逻辑连接),而不是一条真正的物理连接。
TCP 报文段先要传送到 IP 层,加上 IP 首部后,再传送到数据链路层。
再加上数据链路层的首部和尾部后,才离开主机发送到物理链路。

图中指出,TCP 和 UDP 再发送报文时所采用的方式完全不同。
TCP 并不关心应用进程一次把多长的报文发送到 TCP 的缓存中,而是根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP发送的报文长度是应用进程给出的)。
如果应用进程传送到 TCP 缓存的数据块太长,TCP 就可以把它划分短一些再传送。
如果应用进程一次只发来一个字节,TCP 也可以等待积累有足够多的字节后再构成报文段发送出去。

TCP 的连接

TCP 把连接作为最基本的抽象。TCP 的许多特性都与 TCP 是面向连接的这个基本特性有关。因此我们对 TCP 连接需要有更清楚的了解。

每一条 TCP 连接有两个端点。那么,TCP 连接的端点是什么呢?不是主机,不是主机的 IP 地址,不是应用进程,也不是运输层的协议端口。
TCP 连接的端点叫做套接字(socket)或插口。
根据 RFC 793 的定义:端口号拼接到 IP 地址即构成了套接字。
因此,套接字的表示方法是在点分十进制的 IP 地址后面写上端口号,中间用冒号或逗号隔开。
例如,若 IP 地址是 192.13.4.5 而端口号是 80,那么得到的套接字就是(192.3.4.5:80)。
总之我们有:

套接字 socket = ( IP 地址: 端口号 )

每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定。即

TCP 连接 ::= { socket1, socket2 } = { (IP1: port1), (IP2: port2) }

这里 IP1 和 IP2 分别是两个端点主机的 IP 地址,而 port1 和 port2 分别是两个端点主机中的端口号。
TCP 连接的两个套接字就是 socket1 和 socket2。可见套接字 socket 是个很抽象的概念。

总之,TCP 连接就是由协议软件所提供的一种抽象。
虽然有时为了方便,我们也可以说,在一个应用进程和另一个应用进程之间建立一条 TCP 连接,但一定要记住:TCP 连接的端点是个很抽象的套接字,即(IP 地址: 端口号)。
也还应记住:同一个 IP 地址可以有多个不同的 TCP 连接,而同一个端口号也可以出现在多个不同的 TCP 连接中。

请注意,socket 这个名词有时容易使人把一些概念弄混淆,因为随着互联网的不断发展以及网络技术的进步,同一个名词 socket 却可表示多种不同的意思。例如

(1) 允许应用程序访问连网协议的应用编程接口 API,即运输层和应用层之间的一种接口,称为 socket API,并简称为 socket
(2) 在 socket API 中使用的一个函数名也叫做 socket
(3) 调用 socket 函数的端点称为 socket,如“创建一个数据报 socket”
(4) 调用 socket 函数时,其返回值称为 socket 描述符,可简称为 socket
(5) 在操作系统内核中连网协议的 Berkeley 实现,称为 socket 实现。

上面的这些 socket 的意思都和 RFC 793 定义的 socket(指端口号拼接到 IP 地址)不同。

可靠传输的工作原理

我们知道,TCP 发送的报文段时交给 IP 层传送的。但 IP 层只能提供尽最大努力服务。

也就是,TCP 下面的网络所提供的是不可靠的传输。因此,TCP 必须采用适当的措施才能使得两个运输层之间的通信变得可靠。

理想的传输条件有以下两个特点:

(1) 传输信道不产生差错
(2) 不管发送方以多块的速度发送数据,接收方总是来得及处理收到的数据。

在这样的理想传输条件下,不需要采取任何措施就能够实现可靠传输。

然而实际的网络都不具备以上两个理想条件。但我们可以使用一些可靠传输协议,当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当降低发送数据的速度。
这样一来,本来不可靠的传输信道就能够实现可靠传输了。

TCP 报文段的首部格式

TCP 虽然是面向字节流的,但 TCP 传送的数据单元却是报文段。
一个 TCP 报文段分为首部和数据两部分,而 TCP 的全部功能都体现在它首部中各字段的作用
因此,只有弄清 TCP 首部各字段的作用次啊能掌握 TCP 的工作原理

TCP报文段的首部格式

TCP 报文段首部的前 20 个字节是固定的,后面有 4n 字节是根据需要而增加的选项(n 是整数)。因此 TCP 首部的最小长度是 20 字节。

首部固定部分各字段的意义如下:

(1) 源端口和目的端口各占 2 个字节,分别写入源端口号和目的端口号。

(2) 序号占 4 字节。序号范围是 [0, 2^{32} - 1],共 2^{32}(即 4294967296)个序号。
序号增加到 2^{32} - 1 后,下一个序号就又回到 0。也就是说,序号使用 mod 2^{32} 运算。TCP 是面向字节流的。
在一个 TCP 连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。
首部中的序号字段值则指的是本报文所发送的数据的第一个字节的序号。
例如,一报文段的序号字段值是 301,而携带的数据共有 100 字节。
这就表明:本报文段的数据的第一个字节的序号是 301,最后一个字节的序号是 400.
显然,下一个报文段(如果还有的话)的数据序号应当从 401 开始,即下一个报文段的序号字段值应为 401.
这个字段的名称也叫做“报文段序号

(3) 确认号占 4 字节,是期望收到对方下一个报文段的第一个数据字节的序号。
例如,B 正确收到了 A 发送过来的一个报文段,其序号字段值是 501,而数据长度是 200 字节(序号 501 到 700),这表明 B 正确收到了 A 发送的到序号 700 为止的数据。
因此,B 期望收到 A 的下一个数据序号是 701,于是 B 在发送给 A 的确认报文段中把确认号置为 701。请注意,现在的确认号不是 501,也不是 700,而是 701.
总之,应当记住:

如果确认号 = N,则表明:到序号 N - 1 为止的所有数据都已正确收到

由于序号字段有 32 位长,可对 4GB(即 4 千兆字节)的数据进行编号。
在一般情况下可保证当序号重复使用时,旧序号的数据早已通过网络到达终点了。

(4) 数据偏移占 4 位,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。
这个字段实际上是指出 TCP 报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。
但应注意,“数据偏移”的单位是 32 位字(即以 4 字节长的字位计算单位)。
由于 4 位二进制数能够表示的最大十进制数字是 15,因此数据偏移的最大值是 60 字节,这也是 TCP 首部的最大长度(即选项长度不能超过 40 字节)

(5) 保留占 6 位,保留位今后使用,但目前应置为 0.

下面有 6 个控制位,用来说明本报文段的性质,它们的意义见下面的 (6) 到 (11)

(6) 紧急 URG(URGent) 当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不要按原来的排队顺序来传送。
例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行。
因此用户从键盘发出中断命令(Control + C)。如果不使用紧急数据,那么这两个字符将存储在接收 TCP 的缓存末尾。
只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了许多时间。

当 URG 置 1 时,发送应用进程就告诉发送方的 TCP 有紧急数据要传送。
于是发送方 TCP 就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。
这时要与首部中紧急指针字段配合使用。

然而在紧急指针字段的具体实现上,由于过去的有些文档有错误或有不太明确的地方,因而导致对有关的 RFC 文档产生了不同的理解。
于是,在 2011 年公布的建议标准 RFC 6093,把紧急指针字段的使用方法做出了更加明确的解释,并更新了几个重要的 RFC 文档,如 RFC 793,RFC 1011,RFC 1122 等

(7) 确认 ACK(ACKnowledgment)仅当 ACK = 1 时确认号字段才有效。当 ACK = 0 时,确认号无效。
TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置 1.

(8) 推送 PSH(PuSH)当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。
在这种情况下,TCP 就可以使用推送(push)操作。这时,发送方 TCP 把 PSH 置 1,并立即创建一个报文段发送出去。
接收方 TCP 收到 PSH = 1 的报文段,就尽快地(即“推送”向前)交付接收应用进程,而不再等到整个缓存都填满了后再向上交付

虽然应用程序可以选择推送操作,但推送操作很少使用

(9) 复位 RST(ReSeT)当 RST = 1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
RST 置 1 还用来拒绝一个非法的报文段或拒绝打开一个连接。RST 也可称为重建位或重置位。

(10) 同步 SYN(SYNchronization)在连接建立时用来同步序号。当 SYN = 1ACK = 0 时,表明这是一个连接请求报文段。
对方若同意建立连接,则应在响应的报文段中使 SYN = 1ACK = 1
因此, SYN 置为 1 就表示这是一个连接请求或连接接受报文。

(11) 终止 FIN(FINis,意思是“完”、“终”)用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接

(12) 窗口占 2 字节。窗口值时 [0, 2^{16} - 1] 之间的整数。
窗口指的是发送本报文段的一方的接收窗口(而不是自己的发送窗口)。
窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。
总之,窗口值作为接收方让发送方设置其发送窗口的依据。

例如,发送了一个报文段,其确认号是 701,窗口字段是 1000。这就是告诉对方:“从 701 号算起,我(即发送此报文段的一方)的接收缓存空间还可接收 1000 个字节数据(字节序号是 701 到 1700),你在给我发送数据时,必须考虑到这一点。”

总之,应当记住:

窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化着。

(13) 检验和 占 2 字节。检验和字段检验的范围包括首部和数据这两部分。
和 UDP 用户数据报一样,在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。
伪首部的格式与 UDP 用户数据包的伪首部一样。但应把伪首部第 4 个字段中的 17 改为 6(TCP 的协议号是 6),把第 5 字段中的 UDP 长度改为 TCP 长度。
接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用 IPv6,则相应的伪首部也要改变。

(14) 紧急指针 占 2 字节。紧急指针仅在 URG=1 时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)。
因此,紧急指针指出了紧急数据的末尾在报文段中的位置。
当所有紧急数据都处理完时,TCP 就告诉应用程序恢复到正常操作。
值得注意的是,即使窗口为零时也可发送紧急数据。

(15) 选项长度可变,最长可达 40 字节。当没有使用“选项”时,TCP 的首部长度是 20 字节。

TCP 最初只规定了一种选项,即最大报文段长度 MSS(Maximum Segment Size)[RFC 879]。请注意 MSS 这个名词的含义。
MSS 是每一个 TCP 报文段中的数据字段的最大长度。数据字段加上 TCP 首部才等于整个的 TCP 报文段。
所以 MSS 并不是整个 TCP 报文段的最大长度,而是“TCP 报文段长度减去 TCP 首部长度”。

为什么要规定一个最大报文段长度 MSS 呢?这并不是考虑接收方的接收缓存可能放不下 TCP 报文段中的数据。实际上,MSS 与接收窗口值没有关系。
我们知道,TCP 报文段的数据部分,至少要加上 40 字节的首部(TCP 首部 20 字节和 IP 首部 20 字节,这里都还没有考虑首部中的选项部分),才能组装成一个 IP 数据报。
若选择较小的 MSS 长度,网络的利用率就降低。
设想在极端的情况下,当 TCP 报文段只含有 1 字节的数据时,在 IP 层传输的数据报的开销至少有 40 字节(包括 TCP 报文段的首部和 IP 数据报的首部)。
这样,对网络的利用率就不会超过 1/41。到了数据链路层还要加上一些开销。
但反过来,若 TCP 报文段非常长,那么在 IP 层传输时就有可能要分解成多个短数据报片。
在终点要把收到的各个短数据报片装配成原来的 TCP 报文段。当传输出错时还要进行重传。这些也都会使开销增大。

因此,MSS 应尽可能大些,只要在 IP 层传输时不需要再分片就行。
由于 IP 数据报所经历的路径使动态变化的,因此在这条路径上确定的不需要分片的 MSS,如果改走另一条路径就可能需要进行分片。因此最佳的 MSS 是很难确定的。
在连接建立的过程中,双方都把自己能能够支持的 MSS 写入这一字段,以后就按照这个数据值传送数据,两个传送方向可以有不同的 MSS 值。
若主机未填写这一项,则 MSS 的默认值是 536 字节长。
因此,所有在互联网上的主机都应能接受的报文段长度是 536 + 20(固定首部长度) = 556 字节。

TCP 的拥塞控制

拥塞控制的一般原理

在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。
在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。
这种情况就叫做拥塞
可以把出现网络拥塞的条件写成如下的关系式:

对资源的需求总和 > 可用资源

若网络中有许多资源同时呈现供应不足,网络的性能就要明显变坏,整个网络的吞吐量将随着负荷的增大而下降。

有人可能会说:“只要任意增加一些资源,例如,把结点缓存的存储空间扩大,或把链路更换为更高速率的链路,或把结点处理机的运算速度提高,就可以解决网络拥塞的问题。”其实不然。
这是因为网络拥塞是一个非常复杂的问题。
简单地采用上述做法,在许多情况下,不但不能解决拥塞问题,而且还可能使网络的性能更坏。

网络拥塞往往是由许多因素引起的。
例如,当某个结点缓存的容量太小时,到达该结点的分组因无存储空间暂存而不得不被丢弃。
现在设想将该结点缓存的容量扩展到非常大,于是凡到达该结点的分组均可在结点的缓存队列中排队,不受任何限制。
由于输出链路的容量和处理机的速度并未提高,因此在这队列中的绝大多数分组的排队等待时间将会大大增加,结果上层软件只好把它们进行重传(因为早就超时了)。
由此可见,简单地扩大缓存的存储空间同样会造成网络资源的严重浪费,因而解决不了网络拥塞的问题。

又如,处理机处理的速率太慢可能引起网络的拥塞。
简单地将处理机的速率提高,可能会使上述情况缓解一些,但往往又会将瓶颈转移到其他地方。
问题的实质往往是整个系统的各个部分不匹配。只有所有的部分都平衡了,问题才会得到解决。

拥塞常常趋于恶化。如果一个路由器没有足够的缓存空间,它就会丢弃一些新到的分组。
但当分组被丢弃时,发送这一分组的源点就会重传这一分组,甚至可能还要重传多次。
这样会引起更多的分组流入网络和被网络中的路由器丢弃。
可见拥塞引起的重传并不会缓解网络的拥塞,反而会加剧网络的拥塞。

拥塞控制与流量控制的关系密切,它们之间也存在着一些差别。
所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网路中的路由器或链路不致过载。
拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。
拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。
但 TCP 连接的端点只要迟迟不能收到对方的确认信息,就猜想在当前网络中的某处很可能发生了拥塞,但这时却无法知道拥塞到底发生在网络的何处。(是访问某个服务器的通信量过大?还是在某个地区出现自然灾害?)

相反,流量控制往往是指点对点通信量的控制,是个端到端的问题(接收端控制发送端)。
流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。

可以用一个简单例子说明这种区别。
设某个光纤网络的链路传输速率为 1000Gbit/s。
有一台巨型计算机向一台个人电脑以 1G bit/s 的速率传送文件。
显然,网络本身的带宽是足够大的,因而不存在产生拥塞的问题。
但流量控制却是必需的,因为巨型计算机必须经常停下来,以便使个人电脑来得及接收。

但如果有另一个网络,其链路传输速率为 1 Mbit/s,而有 1000 台大型计算机连接在这个网络上。
假定其中的 500 台计算机分别向其余的 500 台计算机以 100kbit/s 的速率发送文件。
那么现在的问题已不是接收端的大型计算机是否来得及接收,而是整个网络的输入负载是否超过网络所能承受的。

拥塞控制和流量控制之所以常常被弄混,是因为某些拥塞控制算法是向发送端发送控制报文,并告诉发送端,网络已出现麻烦,必须放慢发送速率。
这点又和流量控制是很相似的。

TCP 的拥塞控制方法

TCP 进行拥塞控制的算法有四种,即慢开始(slow-start)拥塞避免(congestion avoidance)快重传(fast retransmit)快恢复(fast recovery)(见 2009 年 9 越公布的草案标准 RFC 5681)。

TCP 的运输连接管理

TCP 是面向连接的协议。运输连接是用来传送 TCP 报文的。
TCP 运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。
因此,运输连接就有三个阶段,即:连接建立、数据传送和连接释放。
运输连接的管理就是使运输连接的建立和释放都能正常地进行。

在 TCP 连接建立过程中要解决以下三个问题

(1) 要使每一方能够确认对方的存在

(2) 要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)

(3) 能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配

TCP 连接的建立采用客户服务器方式。主动发起连接建立的应用进程叫做客户(client),而被动等待连接建立的应用进程叫做服务器(server)。

TCP 的连接建立

TCP 建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个 TCP 报文段。
下图画出了三报文握手建立 TCP 连接的过程

用三报文握手建立TCP连接

假定主机 A 运行的是 TCP 客户程序,而 B 运行 TCP 服务器程序。
最初两端的 TCP 进程都处于 CLOSED(关闭) 状态。图中在主机下面的方框分别是 TCP 进程所处的状态。
请注意,在本例中,A 主动打开连接,而 B 被动打开连接。

一开始,B 的 TCP 服务器进程先创建传输控制快 TCB,准备接受客户进程的连接请求。
然后服务器进程就处于 LISTEN(收听)状态,等待客户的连接请求。如有,即作出响应。

(1) A 的 TCP 客户进程也是首先创建传输控制模块 TCB。然后,在打算建立 TCP 连接时,向 B 发出连接请求报文段,这时首部中的同步位SYN = 1,同时选择一个初始序号seq = x
TCP 规定,SYN 报文段(即SYN = 1的报文段)不能携带数据,但要消耗掉一个序号。
这时,TCP 客户进程进入 SYN-SENT(同步已发送)状态 ,等待服务器确认

第一次握手

(2) B 收到连接请求报文段后,如同意建立连接,则向 A 发送确认。
在确认报文段中应把 SYN 位 和 ACK 位都置 1,确认号是ack = x + 1,同时也为自己选择一个初始序号seq = y
请注意,这个报文段也不能携带数据,但同样要消耗掉一个序号。
这时 TCP 服务器进程进入 SYN-RCVD(同步收到)状态

第二次握手

(3) TCP 客户进程收到 B 的确认后,还要向 B 给出确认。
确认报文段的 ACK 置 1,确认号ack = y + 1,而自己的序号seq = x + 1
TCP 的标准规定,ACK 报文段可以携带数据。但如果不携带数据则不消耗序号,在这种情况下,下一个数据报文段的序号仍是seq = x + 1
这时,TCP 连接已经建立,A 进入 ESTABLISHED(已建立连接的状态)

当 B 收到 A 的确认后,也进入 ESTABLISHED状态。

第三次握手

上面给出的连接建立过程叫做三报文握手。

请注意,在图中 B 发送给 A 的报文段,也可拆成两个报文段。
可以先发送一个确认报文段(ACK = 1, ack = x + 1),然后再发送一个同步报文段(SYN = 1, seq = y)。
这样的过程就变成了四报文握手,但效果是一样的

下图是我抓包抓到的本地 ip192.168.1.103(屋里有 3 个人,我是第三个进来的,所以我的 ip 地址是 103)和interface.biliapi.com的握手过程。

抓包TCP握手过程

为什么 A 最后还要发送一次确认呢?
这主要是为了防止已失效的连接请求报文段突然又传送到了 B,因而产生错误。

所谓“已失效的连接请求报文段”是这样产生的。
考虑一种正常情况,A 发出连接请求,但因连接请求报文丢失而未收到确认。
于是 A 再传送一次连接请求。后来收到了确认,建立了连接。
数据传输完毕后,就释放了连接。A 共发送了两个连接请求报文段,其中第一个丢失,第二个到达了 B,没有“已失效的连接请求报文段”

现假定出现一种异常情况,即 A 发出的第一个连接请求报文段并没有丢失,而是在某些网络结点长时间滞留了,以致延误到连接释放以后的某个时间才到达 B。
本来这是一个早已失效的报文段。但 B 收到此失效的连接请求报文段后,就误认为是 A 又发出一次新的连接请求。
于是就向 A 发出确认报文段,同意建立连接。假定不采用报文握手,那么只要 B 发出确认,新的连接就建立了。

由于现在 A 并没有发出建立连接的请求,因此不会理睬 B 的确认,也不会向 B 发送数据。
但 B 却以为新的数据连接已经建立了,并一直等待 A 发来数据。B 的许多资源就这样白白浪费了。

采用三报文握手的办法,可以防止上述现象的发生。
例如在刚才的异常情况下,A 不会向 B 的确认发出确认。B 由于收不到确认,就知道 A 并没有要求建立连接。

分析握手过程中字段的变化

我们知道每一次握手时,TCP 报文中标志位的值是不同的。为了更好地分析 3 次握手时每个标志位的变化,下面以抓包方式分析每个数据包的信息

使用 Wireshark 捕获 TCP 连接数据包并进行分析:

(1) 捕获到 3 次握手包,如图所示,图中,第 22 个数据包的源 IP 地址为 192.168.59.135,目标 IP 地址为 192.168.59.131。
在 Transmssion Control Protocol 中可以看到,Flags 为 SYN,并且值设置为 1,表示该数据包时主机 192.168.59.135 向主机 192.168.59.131 发起的请求,希望建立 TCP 连接。
Sequence number 表示请求序列号 seq,值为 0,是由主机 192.168.59.135 随机生成的

第一次握手抓包

(2) 选择第 23 个数据包进行查看,如图所示。该数据包源 IP 地址为 192.168.59.131,目标 IP 地址为 192.168.59.135。
在 Transmission Control Protocol 中可以看到,Flags 为 (SYN, ACK),并且将 SYN 置为 1,表示该数据包是主机 192.168.59.131 用来回复主机 192.168.59.135 发送的 TCP 连接请求。Acknowledgment number 表示确认号 ack,值为 1.
该值是回复主机 192.168.59.135 发来的连接请求 seq,因此在 seq 的基础上加 1,以代表确认。
Sequence number 值为 0,该值是由主机 192.168.59.131 生成的,是向主机 192.168.59.135 发送的 seq,表示同意该主机发来的连接请求

第二次握手抓包

(3) 选择第 24 个数据包进行查看,如图所示。源 IP 地址为 192.168.59.135,目标 IP 地址为 192.168.59.131。
在 Transmission Control Protocol 中可以看到,Flags 为 ACK。表示该数据包是主机 192.168.59.135 对主机 192.168.59.131 发来的同意连接数据包后做出的确认回复。Acknowledgment number(确认号) 的值为 1,该值是主机 192.168.59.131 发来的 seq 的基础上加 1 得到的。
Sequence number 的值为 1,表示收到主机 192.168.59.131 发来的同意连接数据包后,再次向该主机发送连接请求,表示要连接了。

第三次握手抓包

TCP 的连接释放

TCP 连接释放过程比较复杂,我们仍结合双方状态的改变来阐明连接释放的过程。

数据传输结束后,通信的双方都可释放连接。
现在 A 和 B 都处于 ESTABLISHED 状态。

TCP连接释放的过程

(1) 第一次挥手

A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接。
A 把连接释放报文段首部的终止控制位 FIN 置 1,其序号 seq = u,它等于前面已传送过的数据的最后一个字节的序号加 1.
这时 A 进入 FIN-WAIT-1(终止等待 1)状态,等待 B 的确认。
请注意,TCP 规定,FIN 报文段即使不携带数据,它也消耗掉一个序号。

(2) 第二次挥手

B 收到连接释放报文段后即发出确认,确认号是ack = u + 1,而这个报文段自己的序号是 v,等于 B 前面已传送过的数据的最后一个字节的序号加 1.
然后 B 就进入 CLOSE-WAIT(关闭等待)状态
TCP 服务器进程这时应通知高层应用程序,因为从 A 到 B 这个方向的连接就释放了,这时的 TCP 连接处于半关闭状态,即 A 已经没有数据要发送了,但 B 若发送数据,A 仍要接收。
也就是说,从 B 到 A 这个方向的连接并未关闭,这个状态可能会维续一段时间。

(3) 第三次挥手

A 收到来自 B 的确认后,就进入 FIN-WAIT-2(终止等待 2)状态,等待 B 发出的连接释放报文段。

若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接。这时 B 发出的连接释放报文段必须使 FIN = 1。
现假定 B 的序号为 w(在半关闭状态 B 可能又发送了一些数据)。
B 还必须重复上次已发送过的确认号ack = u + 1
这时 B 就进入 LAST-ACK(最后确认)状态,等待 A 的确认。

(4) 第四次挥手

A 在收到 B 的连接释放报文段后,必须对此发出确认。在确认报文段中把 ACK 置 1,确认号 ack = w + 1,而自己的序号是 seq = u + 1(根据 TCP 标准,前面发送过的 FIN 报文段要消耗一个序号)。
然后进入到 TIME-WAIT(时间等待)状态。请注意,现在 TCP 连接还没有释放掉。必须经过时间等待计时器(TIME-WAIT timer)设置的时候 2MSL 后,A 才进入到 CLOSED 状态。时间 MSL 叫做最长报文段寿命(Maximum Segment Lifetime),RFC 793 建议设为 2 分钟。但这完全是从工程上来考虑的,对于现在的网络,MSL = 2 分钟可能太长了些。
因此 TCP 允许不同的实现可根据具体情况使用更小的 MSL 的值。
因此,从 A 进入到 TIME-WAIT 状态后,要经过 4 分钟才能进入到 CLOSED 状态,才能开始建立下一个新的连接。
当 A 撤销相应的传输控制块 TCB 后,就结束了这次的 TCP 连接。

为什么 A 的 TIME-WAIT 状态必须等待 2MSL 的时间呢?这有两个理由。

第一,为了保证 A 发送的最后一个 ACK 报文段能够到达 B。这个 ACK 报文段有可能丢失,因而使处在 LAST-ACK 状态的 B 收不到对已发送的 FIN + ACK 报文段的确认。
B 会超时重传这个 FIN + ACK 报文段,而 A 就能在 2MSL 时间内收到这个重传的 FIN + ACK 报文段。
接着 A 重传一次确认,重新启动 2MSL 计时器。最后,A 和 B 都正常进入到 CLOSED 状态。
如果 A 在 TIME-WAIT 状态不等待一段时间,而是在发送完 ACK 报文段后立即释放连接,那么就无法收到 B 重传的 FIN + ACK 报文段,因而也不会再发送一次确认报文段。这样,B 就无法按照正常步骤进入 CLOSED 状态。

第二,防止“已失效的连接请求报文段”出现在本连接中。A 在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。
这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

B 只要收到了 A 发出的确认,就进入 CLOSED 状态。
同样,B 在撤销相应的传输控制块 TCB 后,就结束了这次的 TCP 连接。
我们注意到,B 结束 TCP 连接的时候要比 A 早一些。

上述的 TCP 连接释放过程是四报文握手

除时间等待计时器外,TCP 还设有一个保活计时器(keepalive timer)。设想有这样的情况:客户已主动与服务器建立了 TCP 连接。但后来客户端的主机突然出故障。
显然,服务器以后就不能再收到客户发来的数据。因此,应当有措施使服务器不要再白白等待下去。这就是使用保活计时器。
服务器每收到一次客户的数据,就重新设置保活计时器,时间的设置通常是两小时。
若两小时没有收到客户的数据,服务器就发送一个探测报文段,以后则每隔 75 秒钟发送一次。
若一连发送 10 个探测报文段后仍无客户的响应,服务器就认为客户端出了故障,接着就关闭这个连接。

小结

  • 运输层提供应用进程间的逻辑通信,也就是说,运输层之间的通信并不是真正在两个运输层之间直接传送数据。运输层向应用层屏蔽了下面网络的细节(如网络拓扑、所采用的路由选择协议等),它使应用进程看见的就是好像在两个运输层实体之间有一条端到端的逻辑通信信道。
  • 网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信
  • 运输层有两个主要的协议:TCP 和 UDP。它们都有复用和分用,以及检错的功能。当运输层采用面向连接的 TCP 协议时,尽管下面的网络是不可靠的(只提供尽最大努力服务),但这种逻辑通信信道就相当于一条全双工通信的可靠信道。当运输层采用无连接的 UDP 协议时,这种逻辑通信信道仍然是一条不可靠信道。
  • 运输层用一个 16 位端口号来标志一个端口。端口号只具有本地意义,它只是为了标志本计算机应用层中的各个进程在和运输层交互时的层间接口。在互联网的不同计算机中,相同的端口号是没有关联的。
  • 两台计算机中的进程要互相通信,不仅要知道对方的 IP 地址(为了找到对方的计算机),而且还要知道对方的端口号(为了找到对方计算机中的应用进程)
  • 运输层的端口号分为服务器端使用的端口号(0 到 1023 指派给熟知端口,1024 到 49151 是登记端口号)和客户端暂时使用的端口号(49152 到 65535)
  • UDP 的主要特点是:(1) 无连接;(2)尽最大努力交付;(3)面向报文;(4)无拥塞控制;(5)支持一对一、一对多、多对一和多对多的交互通信;(6)首部开销小(只有四个字段:源端口、目的端口、长度、检验和)
  • TCP 的主要特点是:(1)面向连接;(2)每一条 TCP 连接只能是点对点的(一对一);(3)提供可靠交付的服务;(4)提供全双工通信;(5)面向字节流。
  • TCP 用主机的 IP 地址加上主机上的端口号作为 TCP 连接的端口。这样的端点就叫做套接字(socket)或插口。套接字用(IP 地址:端口号)来表示
  • 停止等待协议能够在不可靠的传输网络上实现可靠的通信。每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。分组需要进行编号。
  • 超时重传是指只要超过了一段时间仍然没有收到确认,就重传前面发送过的分组(认为刚才发送的分组丢失了)。因此每发送完一个分组需要设置一个超时计时器,其重传时间应比数据在分组传输的平均往返时间更长一些。这种自动重传方式常称为自动重传请求 ARQ
  • 在停止等待协议中,若接收方收到重复分组,就丢弃该分组,但同时还要发送确认。
  • 连续 ARQ 协议可提高信道利用率。发送方维持一个发送窗口,凡位于发送窗口内的分组都可连续发送出去,而不需要等待对方的确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已正确收到了。
  • TCP 报文段首部的前 20 个字节是固定的,后面有 4N 字节是根据需要而增加的选项(N是整数)。在一个 TCP 连接中传送的字节流中的每一个字节都按顺序编号。首部中的序号字段值则指的是本报文段所发送的数据的第一个字节的序号。
  • TCP 首部中的确认号是期望收到对方下一个报文段的第一个数据字节的序号。若确认号为 N,则表明:到序号 N - 1 为止的所有数据都已正确收到
  • TCP 首部中的窗口字段指出了现在允许对方发送的数据量。窗口值是经常在动态变化着的。
  • TCP 使用滑动窗口机制。发送窗口里面的序号表示允许发送的序号。发送窗口后沿的后面部分表示已发送且已收到了确认,而发送窗口前沿的前面部分表示不允许发送。发送窗口后沿的变化情况有两种可能,即不动(没有收到新的确认)和前移(收到了新的确认)。发送窗口前沿通常是不断向前移动的。
  • 流量控制就是让发送方的发送频率不要太快,要让接收方来得及接收
  • 在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫拥塞。拥塞控制就是防止过多的数据注入到网路中,这样可以使网络中的路由器或链路不致过载。
  • 流量控制是一个端到到的问题,是接受端抑制发送端发送数据的速率,以便使接收端来得及接收。拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。
  • 为了进行拥塞控制,TCP 的发送方要维持一个拥塞窗口 swnd 的状态变量。拥塞窗口的大小取决于网络的拥塞程序,并且动态地在变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接收窗口中较小的一个。
  • TCP 的拥塞控制采用了四种算法,即慢开始、拥塞避免、快重传和快恢复。在网络层,也可以使路由器采用适当的分组丢弃策略(如主动队列管理 AQM),已减少网络拥塞的发生。
  • 运输连接有三个阶段,即:连接建立、数据传送和连诶释放。
  • 主动发起 TCP 连接建立的应用进程叫做客户,而被动等待连接建立的应用进程叫做服务器。TCP 的连接建立采用三报文握手机制。服务器要确认客户的连接请求,然后客户要对服务器的确认进行确认。
  • TCP 的连接释放采用四报文握手机制。任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后就进入半关闭状态。当另一方也没有数据再发送时,则发送连接释放通知,对方确认后就完全关闭了 TCP 连接