《计算机网络:自顶向下方法》读书笔记 2:应用层和运输层

1 应用层

网络应用是计算机网络存在的理由,如果我们不能构想出任何有用的应用,也就没有任何必要去设计支持它们的网络协议了。

1.1 网络应用程序体系结构

两种主流的网络应用程序体系结构:客户-服务器体系结构、对等(P2P)体系结构。
客户-服务器体系结构:有一个总是打开的主机称为服务器,它服务于来自许多其他称为客户的主机的请求。在一个客户-服务器应用中,常常会出现一台单独的服务器主机跟不上它所有客户请求的情况,为此,配备大量主机的数据中心常被用于创建强大的虚拟服务器。
P2P体系结构:对位于数据中心的专用服务器有最小的依赖。相反,应用程序在间接连接的主机对之间使用直接通信,这些主机对被称为对等方。

1.2 进程通信

一个进程可以被认为是运行在端系统中的一个程序。
在两个不同端系统上的进程,通过跨越计算机网络交换报文而相互通信。发送进程生成并向网络中发送报文;接收进程接收这些报文并可能通过将报文发送回去进行响应。
在给定的一对进程之间的通信会话场景中,发起通信的进程被标识为客户,在会话开始时等待联系的进程是服务器。

进程通过一个被称为套接字(socket)的软件接口向网络发送报文和从网络接收报文。
套接字是同一台主机内应用层与运输层之间的接口。由于该套接字是建立网络应用程序的可编程接口,因此套接字也称为应用程序和网络之间的应用程序编程接口(API)。应用程序开发者可以控制套接字在应用层端的一切,但是对该套接字的运输层端几乎没有控制权。
应用程序开发者对于运输层的控制仅限于选择运输层协议,也许能设定几个运输层参数。一旦应用程序开发者选择了一个运输层协议,则应用程序就建立在由该协议提供的运输层服务上。

一个运输层协议能够为调用它的应用程序提供什么样的服务呢?
1 可靠数据传输:分组在计算机网络中可能丢失,而对于一些应用,数据丢失是无法容忍的事情,必须确保由应用程序的一端发送的数据正确、完全地交付给该应用程序的另一端。如果一个协议提供了这样的确保数据交付服务,就认为提供了可靠数据传输。运输层协议能够潜在地向应用程序提供可靠数据传输。
2 吞吐量:运输层协议能够以某种特定的速率提供确保的可用吞吐量。具有吞吐量要求的应用程序被称为带宽敏感的应用。与之相对的是弹性应用。
3 定时:运输层协议也能提供定时保证。
4 安全性:运输协议能够为应用程序提供一种或多种安全性服务。

因特网为应用程序提供两个运输层协议,即UDP和TCP。这两个协议会在运输层详细介绍,在这里只需要知道TCP协议提供了可靠数据传输服务,UDP没有提供可靠数据传输服务即可。

在一台主机上运行的进程为了向在另一台主机上运行的进程发送分组,接收进程需要有一个地址。为了标识该接收进程,需要定义两种信息:
1 主机的地址,由IP地址(IP address)标识。
2 定义在目的主机中的接收进程的标识符,由端口号(port number)标识。

1.3 Web和HTTP

Web指的是万维网(World Wide Web),即全球广域网。
Web是一个引起公众注意的因特网应用,极大地改变了人们与工作环境内外交流的方式。

Web的应用层协议是超文本传输协议(HyperText Transfer Protocol, HTTP),它是Web的核心。
HTTP由两个程序实现:一个客户程序和一个服务器程序。客户程序和服务器程序运行在不同的端系统中,通过交换HTTP报文进行会话。
当用户请求一个Web页面(如点击一个超链接)时,浏览器向服务器发出对该页面中所包含对象的HTTP请求报文,服务器接收到请求并用包含这些对象的HTTP响应报文进行响应。
HTTP使用TCP作为它的支撑运输协议。HTTP客户首先发起一个与服务器的TCP连接,一旦连接建立,该浏览器和服务器进程就可以通过套接字接口访问TCP。
一旦客户向它的套接字接口发送了一个请求报文,该报文就脱离了客户控制并进入TCP的控制。TCP为HTTP提供了可靠数据传输服务,这意味着客户进程发出的每个HTTP请求报文最终能完整地到达服务器;类似地,服务器进程发出的每个HTTP响应报文最终能完整地到达客户。从这里我们可以看到分层体系结构最大的优点是HTTP协议不用担心数据丢失。

注意到,服务器向客户发送被请求的文件,而不存储任何关于该客户的状态信息。假如某个特定用户在几秒钟内两次请求同一个对象,服务器并不会因为刚刚为客户提供了该对象就不再做出反应,而是重新发送该对象。所以我们说HTTP是一个无状态协议。

1.4 HTTP报文格式

HTTP报文分为请求报文和响应报文。

1.4.1 HTTP请求报文

一个典型的HTTP请求报文:
GET /somedir/page.html HTTP/1.1
Host: www.someschool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-Language: fr

HTTP请求报文的第一行叫做请求行,其后继的行叫做首部行。
请求行有3个字段:方法字段、URL字段和HTTP版本字段。
方法字段可以取的值包括GET、POST、HEAD、PUT和DELETE,用的最多的还是GET。
首部行Host: www.someschool.edu指明了对象所在的主机。
首部行Connection: close表示要求服务器在发送完被请求的对象后就关闭这条连接。
首部行User-agent: Mozilla/5.0指明用户代理(即向服务器发送请求的浏览器类型)是Mozilla/5.0,即Firefox浏览器。
首部行Accept-language: fr表示用户想得到该对象的法语版本。

下图是一个请求报文的通用格式:

图中的请求数据即实体体(entity body),使用GET方法时实体体为空,而使用POST方法时才使用该实体体。
当用户提交表单时,HTTP客户常常会使用POST方法,例如用户向搜索引擎提供搜索关键词时。使用POST报文时,用户仍可以向服务器请求一个Web页面,但Web页面的特定内容依赖于用户在表单字段中输入的内容。如果方法字段的值为POST时,则实体体中包含的就是用户在表单字段中的输入值。
HEAD方法类似于GET方法。当服务器收到使用HEAD方法的请求时,将会用一个HTTP报文进行响应,但是并不返回请求对象。应用程序开发者常用HEAD方法进行调试跟踪。
PUT方法常与Web发行工具联合使用,它允许用户上传对象到指定的Web服务器上指定的路径(目录)。
DELETE方法允许用户或者应用程序删除Web服务器上的对象。

1.4.2 HTTP响应报文

一个典型的HTTP响应报文:
HTTP/1.1 200 OK
Connection: close
Date: Tue, 09 Aug 2011 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 09 Aug 2011 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html

(data data data data data ...)

HTTP响应报文的第一行叫做状态行,其后继的行叫做首部行,然后是实体体。
状态行有3个字段:协议版本字段、状态码和相应状态信息。
实体体是报文的主要部分,它包含了所请求的对象本身。
首部行Connection: close表示发送完报文后将关闭该TCP连接。
首部行Date: 指示服务器产生并发送该响应报文的日期和时间。
首部行Server: Apache/2.2.3 (CentOS)指示该报文是由一台Apache Web服务器产生的。
首部行Last-Modified: 指示了对象创建或者最后修改的日期和时间。
首部行Content-Length: 6821指示了被发送对象中的字节数是6821。
首部行Content-Type: text/html指示了实体体中的对象是HTML文本。

下图是一个响应报文的通用格式:

 

其中状态码指示了请求的结果,一些常见的状态码包括:
200 OK:请求成功,信息在返回的响应报文中。
301 Moved Permanently:请求的对象已经被永久转移了,新的URL定义在响应报文的Location: 首部行中。客户软件将自动获取新的URL。
400 Bad Request:该请求不能被服务器理解。
404 Not Found:被请求的文档不在服务器上。
505 HTTP Version Not Supported:服务器不支持请求报文使用的HTTP协议版本。

1.5 cookie

一个Web站点通常希望能够识别用户,可能是因为服务器希望限制用户的访问,或者因为它希望把内容与用户身份联系起来。为此,HTTP使用了cookie,它允许站点对用户进行跟踪。

cookie技术有4个组件:
1 在HTTP响应报文中的一个cookie首部行。
2 在HTTP请求报文中的一个cookie首部行。
3 在用户端系统中保留有一个cookie文件,并由用户的浏览器进行管理。
4 位于Web站点的一个后端数据库。

 

假设Susan总是使用IE浏览器上网,她曾经访问过eBay站点,现在她首次与Amazon.com联系。
当请求报文到达Amazon Web服务器时,服务器会为用户(Susan的主机)创建一个唯一识别码,并以此作为索引在它的后端数据库中产生一个表项。
接下来,Amazon Web服务器用一个包含Set-cookie: 首部的HTTP响应报文对Susan的浏览器进行响应,其中Set-cookie: 首部包含唯一识别码。
当Susan的浏览器收到该HTTP响应报文时,会在它管理的特定cookie文件中添加一行,该行包含服务器的主机名和在Set-cookie: 首部中的识别码。
当Susan继续浏览Amazon网站时,每请求一个Web页面,其浏览器就会从该cookie文件中获取她对这个网站的识别码,并放到HTTP请求报文中包括识别码的cookie首部行中。
这样,Amazon服务器可以跟踪Susan在Amazon站点的活动。它可以确切地知道该用户按照什么顺序、在什么时间、访问了哪些页面。Amazon使用cookie来提供它的购物车服务。
如果Susan在一个星期后再次访问Amazon站点,她的浏览器会在其请求报文中继续放入她对这个网站的识别码。Amazon将根据Susan过去在Amazon访问的网页向她推荐产品。如果Susan在Amazon注册过,即提供了她的全名、电子邮件地址、邮政地址和银行卡账号,则Amazon能将其数据库中的这些信息与识别码相关联。这样当Susan在后续的访问中选择购买某件商品时,就不必再输入姓名、银行卡账号或者地址等信息了。

1.6 Web缓存

Web缓存器(Web cache)也叫代理服务器(proxy server),它是能够代表初始Web服务器来满足HTTP请求的网络实体。
Web缓存器有自己的磁盘存储空间,并在存储空间中保存最近请求过的对象的副本。
假设浏览器要请求一个对象,它会先建立一个到Web缓存器的TCP连接,并向Web缓存器中的对象发送一个HTTP请求,Web缓存器会检查本地是否存储了该对象副本,如果有,就向客户浏览器用HTTP响应报文返回该对象;如果没有,它就打开一个与该对象的初始服务器的TCP连接,在这个连接上发送一个对该对象的HTTP请求。在收到该请求后,初始服务器向该Web缓存器发送具有该对象的HTTP响应。当Web缓存器接收到该对象时,它在本地存储空间存储一份副本,并向客户的浏览器用HTTP响应报文发送该副本。

在因特网上部署Web缓存器有两个原因。首先,Web缓存器可以大大减少对客户请求的响应时间。其次,Web缓存器能够大大减少一个机构的接入链路到因特网的通信量。

不过使用高速缓存可能会带来一个问题是,存放在缓存器中的对象副本可能是陈旧的版本。对此HTTP的解决办法是,缓存器在存储对象时,同时也存储对象的最后修改日期,一段时间后,另一个用户经过缓存器请求同一个对象时,如果认为缓存器中的对象可能已经被修改,缓存器向服务器发送一个条件GET请求执行最新检查,在这个请求中包含一个If-Modified-Since: 首部行,告诉服务器,仅当指定日期之后该对象被修改过,才发送该对象,如果没有修改过,则发送一个状态码304 Not Modified的响应报文。

1.7 文件传输协议:FTP

FTP使用了两个并行的TCP连接来传输文件,一个是控制连接,一个是数据连接。因为FTP协议使用一个独立的控制连接,所以我们也称FTP的控制信息是带外传送的。

当用户主机与远程主机开始一个FTP会话时,FTP的客户(用户)端首先在服务器21号端口与服务器(远程主机)端发起一个用于控制的TCP连接。FTP的客户端可以通过该控制连接发送用户的标识和口令,当FTP的服务器端从该连接上收到一个文件传输的命令后,就发起一个到客户端的TCP数据连接,FTP在该数据连接上准确地传送一个文件,然后关闭该连接。在同一个会话期间,如果用户还需要传输另一个文件,FTP则打开另一个数据连接。因而对FTP传输而言,控制连接贯通了整个用户会话期间,但是对会话中的每一次文件传输都需要建立一个新的数据连接。
FTP服务器必须在整个会话期间保留用户的状态。特别是,服务器必须把特定的用户账户与控制连接联系起来,随着用户在远程目录树上徘徊,服务器必须追踪用户在远程目录树上的当前位置。对每个进行中的用户会话的状态信息进行追踪,大大限制了FTP同时维持的会话总数。

1.8 电子邮件

因特尔电子邮件系统有3个主要组成部分:用户代理(user agent)、邮件服务器(mail server)和简单邮件传输协议(SMTP)。
用户代理允许用户阅读、回复、转发、保存和撰写报文。
一个典型的邮件发送过程是:从发送方的用户代理开始,传输到发送方的邮件服务器,再传输到接收方的邮件服务器,然后再这里被分发到接收方的邮箱中。如果发送方的服务器不能将邮件交付给接收方的服务器,发送方的邮件服务器在一个报文队列中保持该报文并在以后尝试再次发送。通常每30分组左右进行一次尝试,如果几天后仍不能成功,服务器就删除该报文并以电子邮件的形式通知发送方。
SMTP是因特网电子邮件中主要的应用层协议。它使用TCP可靠数据传输服务,从发送方的邮件服务器向接收方的邮件服务器发送邮件。

我认为这部分内容不重要,所以关于电子邮件的摘录也到此为止。更多关于SMTP、POP3、IMAP协议的内容,遇到了请翻书。

1.9 DNS:因特网的目录服务

通常我们会使用主机名或者IP地址来对因特网上的主机进行标识。人们喜欢便于记忆的主机名标识方式,而路由器喜欢定长的、有着层次结构的IP地址。为了折衷这些不同的偏好,我们使用域名系统(DNS)来进行主机名到IP地址转换的目录服务。
DNS是一个分层的DNS服务器实现的分布式数据库,同时也是一个使得主机能够查询分布式数据库的应用层协议。DNS协议运行在UDP之上,使用53号端口。

1.9.1 DNS工作原理

为了使用户的主机能够将一个HTTP请求报文发送到Web服务器www.bilibili.com,该用户必须获得www.bilibili.com的IP地址。过程为
1 应用程序调用DNS的客户端,并指明需要被转换的主机名www.bilibili.com。
2 用户主机上的DNS接收到主机名后,向DNS服务器发送一个DNS查询报文。
3 经过若干毫秒到若干秒的时延后,用户主机上的DNS接收到DNS回答报文,其中含有对应该主机名的IP地址。
4 这个IP地址被传递到调用DNS的应用程序。

DNS采用了分布式的设计方案。大量的DNS服务器以层次方式组织,分布在全世界范围内。大致说来,有3种类型的DNS服务器:根DNS服务器、顶级域(Top-Level Domain, TLD)DNS服务器和权威DNS服务器。
假定一个DNS客户要决定www.bilibili.com的IP地址,首先与根服务器之一联系,它将返回顶级域名com的TLD服务器的ID地址,然后与这些TLD服务器之一联系,将为bilibili.com返回权威服务器的IP地址,最后该客户与bilibili.com权威服务器之一联系,为www.bilibili.com返回其IP地址。

除了根、TLD和权威DNS服务器外,还有一类重要的DNS,称为本地DNS服务器。每个ISP都有一台本地DNS服务器。当主机发出DNS请求时,该请求被发往本地DNS服务器,本地DNS起着代理的作用,将该请求转发到DNS服务器层次结构中。

为了改善时延性能并减少在因特网上到处传输的DNS报文数量,DNS广泛使用了缓存技术:在一个请求链中,当某DNS服务器接收一个DNS回答时,它能将该回答中的信息缓存在本地存储器中。

1.9.2 DNS资源记录

共同实现DNS分布式数据库的所有DNS服务器存储了资源记录(Resource Record, RR),RR提供了主机名到IP地址的映射,每个DNS回答报文包含了一条或多条资源记录。
资源记录是一个包含了下列字段的4元组:(Name, Value, Type, TTL)。
其中,TTL是该记录的生存时间。我们忽略掉TTL字段,Name和Value的值取决于Type。
如果Type=A,则Name是主机名,Value是该主机名对应的IP地址。
如果Type=NS,则Name是个域(如foo.com),Value是个知道如何获得该域中主机IP地址的权威DNS服务器的主机名。
如果Type=CNAME,则Value是别名为Name的主机对应的规范主机名。
如果Type=MX,则Value是个别名为Name的邮件服务器的规范主机名。

1.9.3 DNS报文

DNS报文只有查询报文和回答报文两种,并且两种报文有着相同的格式。如图所示,DNS报文中各字段的语义如下: 

前12个字节是首部区域。其中:
第一个字段是标识符,是一个16比特的数,用于标识该查询。这个标识符会被复制到对查询的回答报文中,以便让客户用它来匹配发送的请求和接收到的回答。
第二个字段是标志字段,含有若干标志。例如1比特的查询回答标志位指出报文是查询报文(0)还是回答报文(1),每个标志位有不同的含义。
第三到第六个字段是四个数字,问题数、资源记录数、权威资源记录数、附加资源记录数分别指出了在首部后的4类数据区域出现的数量。
首部区域后边还有四个区域:
问题区域包含着正在进行的查询信息。
回答区域包含了对最初请求的名字的资源记录。
权威区域包含了其他权威服务器的记录。
附加区域包含了其他有帮助的记录。

1.9.4 注册域名

假定你创建了一个新创业公司,你必定要做的第一件事是在注册登记机构注册域名。注册登记机构是一个商业实体,它验证域名的唯一性,将域名输入DNS数据库。

1.10 P2P应用

BitTorrent是一种用于文件分发的流行P2P协议。
用BitTorrent的术语来讲,参与一个特定文件分发的所有对等方的集合被称为一个洪流(torrent),在一个洪流中的对等方彼此下载等长度的文件块(chunk),典型的块长度为256KB。当一个对等方首次加入一个洪流时,它没有块。随着时间的流逝,它累积了越来越多的块。当它下载块时,也为其他对等方上载了多个块。一旦某对等方获得了整个文件,它也许(自私地)离开洪流,或(大公无私地)留在该洪流中并继续向其他对等方上载块。同时,任何对等方可能在任何时候仅具有块的子集就离开该洪流,并在以后重新加入该洪流中。

2 运输层

运输层协议为运行在不同主机上的应用进程之间提供了逻辑通信功能。
运输层协议是在端系统中而不是在路由器中实现的。在发送端,运输层将从发送应用程序进程接收到的报文转换成报文段(segment)。实现的方法是将应用报文划分成较小的块,并为每块加上一个运输层首部。然后,在发送端系统中,运输层将这些报文段传递给网络层,网络层将其封装成数据报并向目的地发送。

2.1 UDP和TCP概述

因特网为应用层提供了两种可用运输层协议,即UDP和TCP。
UDP(用户数据报协议)为调用它的应用程序提供了一种不可靠、无连接的服务。TCP(传输控制协议)为调用它的应用程序提供了一种可靠的、面向连接的服务。当设计一个网络应用程序时,该应用程序的开发人员必须指定使用这两种协议中的哪一种。
UDP只提供了两种最低限度的运输层服务:数据交付和差错检查。而TCP在此基础上为应用程序提供了几种附加服务,如可靠数据传输、拥塞控制等。

为什么有时候应用开发人员宁愿在UDP之上构建应用,而不选择在TCP上构建应用呢?
TCP的拥塞控制会导致如因特网电话、视频会议之类的实时应用性能变得很差。

2.2 多路复用与多路分解

每个进程都有一个或多个套接字(socket),它相当于从网络向进程传递数据和从进程向网络传递数据的门户。
在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息从而生成报文段,然后将报文段传递到网络层,所有这些工作称为多路复用。
在接收端,主机的运输层将从网络层收到的报文段分解后,将报文段数据定向到对应进程的套接字的工作称为多路分解。

在主机上的每个套接字能够分配一个端口号,当报文段到达主机时,运输层检查报文段中的目的端口号,并将其定向到相应的套接字。然后报文段中的数据通过套接字进入其所连接的进程。

2.3 无连接运输:UDP

UDP只是做了运输协议能够做的最少工作:UDP从应用进程得到数据,附加上用于多路复用/分解服务的源和目的端口号字段,以及两个其他的字段(下面讨论),然后将形成的报文段交给网络层。

 

UDP首部只有4个字段,每个字段由两个字节组成。
通过源端口号和目的端口号,可以使目的主机将应用数据交给运行在目的端系统中的相应进程。
长度字段指示了在UDP报文段中的字节数(首部加数据)。
检验和字段提供了差错检测功能。这就是说,检验和用于确定当UDP报文段从源到达目的地移动时,其中的比特是否发生了改变。发送方的UDP对报文段中的所有16比特字的和进行反码运算,求和时遇到的任何溢出都被回卷,得到的结果被放在UDP报文段中的检验和字段。在接收方,将报文段中的所有16比特字的和与检验和相加,得到的结果将是1111111111111111。如果这些比特之一是0,那么我们就知道该分组中已经出现了差错。

虽然UDP提供差错检测,但它对差错恢复无能为力。UDP的某种实现只是丢弃受损的报文段;其他实现是将受损的报文段交给应用程序并给出警告。

2.4 可靠数据传输原理

可靠数据传输服务抽象是:数据可以通过一条可靠的信道进行传输。借助于可靠信道,传输数据比特就不会受到损坏(由0变为1,或者相反)或丢失,而且所有数据都是按照其发送顺序进行交付。
实现这种服务抽象是可靠数据传输协议(rdt)的责任。

信道传输可能出现的问题有比特受损、丢包等。
比特受损问题解决方法:
1. 首先,需要一种机制(如检验和)使接收方检测到出现了比特差错。
2. 接收方向发送方提供明确的反馈信息:肯定确认(ACK)或者否定确认(NAK)。
3. 如果发送方收到一个NAK分组,重传出错的分组。
丢包问题解决方法:
不管是数据分组丢失,还是一个ACK丢失,或者只是分组或ACK过度延时,统统重传。为了实现基于时间的重传机制,则需要一个倒计数定时器,在一个给定的时间量过期后,可中断发送方。因此,发送方需要能做到:每次发送一个分组时,便启动一个定时器;响应定时器中断;终止定时器。

冗余分组问题:
ACK和NAK也是有受损或丢失的可能的。
● 当发送方收到含糊不清的ACK或NAK分组时,会重传当前数据分组。这样会在发送方到接收方的信道中引入了冗余分组。
● 在ACK丢失,或者分组或ACK过度延时的情况下,也会重传数据分组引入冗余分组。
冗余分组使接收方不知道它上次所发送的ACK或NAK是否被发送方正确地收到。因此它无法得知接收到的分组是新的分组还是一次重传。
解决这个问题的方法是在数据分组中添加一个序号字段,接收方只需要检查序号即可确定收到的分组是否为一次重传。

流水线技术:
不使用停等方式运行,允许发送方发送多个分组而无需等待确认。如果发送方可以在等待确认之前发送3个报文,其信道利用率会是停等方式的3倍。
流水线技术对可靠数据传输协议带来的影响有:
● 必须增加序号范围,因为每个输送中的分组必须有一个唯一的序号,而且也许有多个在输送中未确认的报文。
● 协议的发送方和接收方两端必须缓存多个分组。发送方最低限度应当能缓冲那些已发送但没有确认的分组,接收方也需要缓存已正确接收的分组。

总结:

2.5 面向连接的运输:TCP

TCP被称为是面向连接的,这是因为在一个应用进程可以开始向另一个应用进程发送数据之前,这两个进程必须先相互“握手”,即它们必须相互发送某些预备报文段,以建立确保数据传输的参数。
TCP连接提供的是全双工服务:如果一台主机上的进程A与另一台主机上的进程B存在一条TCP连接,那么应用层数据就可在从进程B流向进程A的同时,也从进程A流向进程B。
TCP连接总是点对点的,即在单个发送方与单个接收方之间的连接。
TCP连接的建立过程:三次握手。

2.5.1 TCP报文段结构

序号和确认号字段存的是什么?
假设主机A上的一个进程想通过一条TCP连接向主机B上的一个进程发送一个数据流。主机A中的TCP将隐式地对数据流中的每一个字节编号。假定数据流由一个包含500000字节的文件组成,其最大报文段长度(MSS)为1000字节,数据流的首字节编号是0。该TCP将为该数据流构建500000/1000=500个报文段,给第一个报文段分配序号0,第二个报文段分配序号1000,第三个报文段分配序号2000,以此类推。每一个序号被填入到相应TCP报文段首部的序号字段中。
TCP是全双工的,因此主机A在向主机B发送数据的同时,也接收来自主机B的数据。从主机B到达的每个报文段中都有一个序号,主机A填充进报文段的确认号就是主机A期望从主机B收到的下一字节的序号。假设主机A已收到一个来自主机B的包含字节0~535的报文段,以及另一个包含字节900~1000的报文段,由于某种原因,主机A还没有收到字节536~899的报文段。主机A为了重新构建主机B的数据流,仍在等待字节536(和其后的字节)。因此,A到B的下一个报文段将在确认号字段中包含536。因为TCP只确认该流中至第一个丢失字节为止的字节,所以TCP被称为提供累积确认。

2.5.2 可靠数据传输

TCP协议仅使用单一的重传定时器。
TCP发送方的行为可以用3个事件来概括(暂不考虑TCP流量和拥塞控制的限制,且数据传送只在一个方向上进行):
1. 从应用程序接收到数据 => 将数据封装在一个报文段中并交给IP。
2. 超时 => 重传引起超时的报文段,然后重启定时器。
3. 收到来自接收方的ACK => 如果ACK的值y大于当前最早未被确认字节序号sendBase,则sendBase=y。如果此时发送还没有完成(还有未确认的报文段),重启定时器。

场景1:主机A向主机B发送一个报文段。假设该报文段的序号是92,而且包含8字节数据。在发出该报文段后,主机A等待一个来自主机B的确认号为100的报文段。虽然A发出的报文段在主机B上被收到,但从主机B发往主机A的确认报文丢失了。在这种情况下,超时事件就会发生,主机A会重传相同的报文段。当主机B收到该重传的报文段时,它将通过序号发现该报文段包含了早已收到的数据。因此,主机B中的TCP将丢弃该重传的报文段中的这些字节。

场景2:主机A连续发送了两个报文段。第一个报文段序号是92,包含8字节数据;第二个报文段序号是100,包含20字节数据。假定两个报文都完好无损地到达主机B,并且主机B为每一个报文段分别发送一个确认。第一个确认报文的确认号是100,第二个确认报文的确认号是120。现在假设在超时之前这两个报文段中没有一个确认报文到达主机A。当超时事件发生时,主机A重传序号92的第一个报文段,并重启定时器。只要第二个报文段的ACK在新的超时发生以前到达,则第二个报文段将不会重传。

场景3:假设主机A与场景2中完全一样,发送两个报文段。第一个报文段的确认报文在网络丢失,但在超时事件发生之前主机A收到一个确认号为120的确认报文。主机A因而知道主机B已经收到了序号为119及之前的所有字节,所以主机A不会重传这两个报文段中的任何一个。

超时间隔加倍:
每次TCP重传时,将下一次的超时间隔设为先前值的两倍。这么做是为了提供一个形式受限的拥塞控制:定时器过期很可能是由网络拥塞引起的,在拥塞的时候,如果源持续重传分组,会使拥塞更加严重。

快速重传:
超时触发重传存在的问题之一是超市周期可能相对较长。当一个报文段丢失时,这种长超时周期迫使发送方延迟重传丢失的分组,因而增加了端到端时延。为了解决这个问题,发送方通常可在超时事件发生之前通过注意冗余ACK来较好地检测到丢包情况。
当一个比期望序号大的失序报文段到达时,接收方会立即发送一个冗余ACK。如果TCP发送方接收到对相同数据的3个冗余ACK,它会认为跟在这个已被确认过3次的报文段之后的报文段已经丢失。这时,TCP就执行快速重传,即在该报文段的定时器过期之前重传丢失的报文段。

2.5.3 流量控制

一条TCP连接每一侧主机都为该连接设置了接收缓存。如果某应用程序读取缓存数据时相对较慢,而发送方发送地太多、太快,发送的数据就会很容易地使该连接的接收缓存溢出。
TCP为它的应用程序提供了流量控制服务以消除发送方使接收方缓存溢出的可能性。流量控制因此是一个速度匹配服务,即发送方的发送速率与接收方应用程序的读取速率相匹配。

TCP通过让发送方维护一个称为接收窗口的变量来提供流量控制。通俗地说,接收窗口用于给发送方一个指示——该接收方还有多少可用的缓存空间。
假设主机A通过一条TCP连接向主机B发送一个大文件。主机B通过把当前的接收窗口大小(rwnd)放入它发给主机A的报文段接收窗口字段中,通知主机A它在该连接的缓存中还有多少可用空间。主机A为了保证主机B的接收缓存溢出,须保证发送到连接中但未被确认的数据量小于等于rwnd值的大小。
这个方案还存在一个小小的技术问题是,假设主机B的接收缓存已经存满,使得rwnd=0,在将rwnd=0通告给主机A之后,还要假设主机B没有任何数据要发给主机A。此时,即使主机B上的应用进程将缓存清空,TCP并不向主机A发送带有rwnd新值的新报文段,这样,主机A就不可能知道主机B的接收缓存已经有了新的空间,即主机A被阻塞而不能再发送数据。为了解决这个问题,TCP规范中要求:当主机B的接收窗口为0时,主机A继续发送只有一个字节数据的报文段,这些报文段将会被接收方确认。最终缓存将开始清空,并且确认报文里将包含一个非0的rwnd值。

2.5.4 TCP连接管理:万众瞩目的3次握手和4次挥手

客户中的TCP会用以下方式与服务器中的TCP建立一条TCP连接:
第一步:客户端的TCP首先向服务器端的TCP发送一个特殊的TCP报文段。该报文段不包含应用层数据。但是在报文段的首部中的一个标志位(即SYN比特)被置为1。因此,这个特殊报文段被称为SYN报文段。另外,客户会随机地选择一个初始序号(client_isn),并将此编号放置于该起始的TCP SYN报文段的序号字段中。该报文段会被封装在一个IP数据报中,并发送给服务器。
第二步:一旦包含TCP SYN报文段的IP数据报到达服务器主机,服务器会从该数据报中提取出TCP SYN报文段,为该TCP连接分配TCP缓存和变量,并向该客户TCP发送允许连接的报文段。这个允许连接的报文段也不包含应用层数据。但是,在报文段的首部却包含3个重要的信息。首先,SYN比特被置为1。其次,该TCP报文段首部的确认号字段被置为client_isn+1。最后,服务器选择自己的初始序号(server_isn),并将其放置到TCP报文段首部的序号字段中。这个允许连接的报文段实际上表明了:“我收到了你发起建立连接的SYN分组,该分组带有初始序号client_isn。我同意建立该连接。我自己的初始序号是server_isn。”该允许连接的报文段有时被称为SYNACK报文段。
第三步:在收到SYNACK报文段后,客户端也要给该连接分配缓存和变量。客户主机则向服务器发送另外一个报文段;这最后一个报文段对服务器的允许连接的报文段进行了确认(该客户通过将值server_isn+1放置到TCP报文段首部的确认字段中来完成此项工作)。因为连接已经建立了,所以该SYN比特被置为0。该三次握手的第三个阶段可以在报文段负载中携带客户到服务器的数据。
一旦完成了这3个步骤,客户和服务器主机就可以相互发送包括数据的报文段了。在以后每一个报文段中,SYN比特都将被置为0。这种连接创建过程通常被称为3次握手。

4次挥手:参与一条TCP连接的两个进程中的任何一个都能终止该连接。假设某客户打算关闭连接,客户应用进程发出一个关闭连接命令,这会引起客户TCP向服务器进程发送一个特殊的TCP报文段。这个特殊的报文段让其首部中的一个标志位即FIN比特被设置为1。当服务器接收到该报文段后,就向发送方会送一个确认报文段。然后,服务器发送它自己的终止报文段,其FIN比特被置为1。最后,该客户对这个服务器的终止报文段进行确认。此时,在两台主机上用于该连接的所有资源都被释放了。

在一个TCP连接的生命周期内,运行在每台主机中的TCP协议在各种TCP状态之间变迁。

 

2.6 拥塞控制原理

2.6.1 拥塞的原因与代价

拥塞的原因:
链路容量是有限的。
路由器缓存的容量是有限的。

拥塞的代价:
当分组的到达速率接近链路容量时,分组经历巨大的排队时延。
发送方必须执行重传以补偿因为缓存溢出而丢弃的分组。
发送方在遇到大时延时所进行的不必要重传会引起路由器利用其链路带宽来转发不必要的分组副本。
当一个分组沿一条路径被丢弃时,每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量最终被浪费掉了。

2.6.2 拥塞控制方法

我们可根据网络层是否为运输层拥塞控制提供了显示帮助,来区分拥塞控制方法。
端到端拥塞控制:网络层没有为运输层拥塞控制提供显式支持。即使网络中存在拥塞控制,端系统也必须通过对网络行为的观察(如分组丢失或时延)来推断之。
网络辅助的拥塞控制:在网络辅助的拥塞控制中,网络层构件(即路由器)向发送方提供关于网络中拥塞状态的显示反馈信息。这种反馈可以简单地用一个比特来指示链路中的拥塞情况。

2.7 TCP拥塞控制

TCP必须使用端到端拥塞控制而不是使用网络辅助的拥塞控制,因为IP层不会向端系统提供显式的网络拥塞反馈。
TCP所采用的方法是让每一个发送方根据感知到的网络拥塞程度来限制其能向连接发送流量的速率。如果一个TCP发送方感知从它到目的地之间的路径上没什么拥塞,则TCP发送方增加其发送速率;如果发送方感知沿着该路径有拥塞,则发送方就会降低其发送速率。这种方法提出了三个问题。第一,一个TCP发送方如何限制它向其连接发送流量的速率呢?第二,一个TCP发送方如何感知从它到目的地之间的路径上存在拥塞呢?第三,当发送方感知到端到端的拥塞时,采用何种算法来改变其发送速率呢?

一个TCP发送方如何限制它向其连接发送流量的速率呢?
运行在发送方的TCP拥塞控制机制跟踪一个额外的变量,即拥塞窗口cwnd。在一个发送方中未被确认的数据量不会超过cwnd与rwnd中的最小值。通过调节cwnd的值,发送方因此能调整它向连接发送数据的速率。
一个TCP发送方如何感知从它到目的地之间的路径上存在拥塞呢?
要么出现超时,要么收到来自接收方的3个冗余ACK。
当发送方感知到端到端的拥塞时,采用何种算法来改变其发送速率呢?
TCP拥塞控制算法。该算法包括3个主要部分:慢启动、拥塞避免、快速恢复。

2.7.1 慢启动

当一条TCP连接开始时,cwnd的值通常初始置为一个MSS(最大报文段长度)的较小值,这就使得初始发送速率大约为MSS/RTT(RTT为往返时延)。由于对于TCP发送方而言,可用带宽可能比MSS/RTT大得多,TCP发送方希望迅速找到可用带宽的数量。因此,在慢启动状态,cwnd的值以1个MSS开始并且每当传输的报文段首次被确认就增加1个MSS。这一过程每过一个RTT,发送速率就翻番。因此,TCP发送速率起始慢,但在慢启动阶段以指数增长。

何时结束这种指数增长呢?慢启动对这个问题提供了几种答案(据我观察,下面的三个答案是串行的)。
答案一:首先,如果存在一个由超时指示的丢包事件(即拥塞),TCP发送方将cwnd设置为1并重新开始慢启动过程。它还将第二个状态变量的值ssthresh(慢启动阈值的速记)设置为cwnd/2,即当检测到拥塞时将ssthresh置为拥塞窗口值的一半。
答案二:直接与ssthresh的值相关联。因为当检测到拥塞时ssthresh设为cwnd的值一半,当到达或超过ssthresh的值时,继续使cwnd翻番可能有些鲁莽。因此,当cwnd的值等于ssthresh时,结束慢启动并且TCP转移到拥塞避免模式。
答案三:如果检测到3个冗余ACK,这时TCP执行一种快速重传并进入快速恢复状态。

2.7.2 拥塞避免

一旦进入拥塞避免状态,cwnd的值大约是上次遇到拥塞时的值的一半,即距离拥塞可能并不遥远。因此,TCP无法每过一个RTT再将cwnd的值翻番,而是采用了一种较为保守的方法,每个RTT只将cwnd的值增加一个MSS。一种通用的方法是对于TCP发送方无论何时到达一个新的确认,就将cwnd增加一个MSS(MSS/cwnd)字节。例如,如果MSS是1460字节并且cwnd是14600字节,则在一个RTT内发送10个报文段。每个到达ACK增加1/10MSS个拥塞窗口长度,因此在收到对所有10个报文段的确认后,拥塞窗口的值将增加一个MSS。

何时结束这种线性增长呢?当出现超时时,TCP的拥塞避免算法行为相同。与慢启动的情况一样,cwnd的值被设置为1个MSS,当丢包事件出现时,ssthresh的值被更新为cwnd值的一半。然而,前面讲过丢包事件也能由一个三个冗余ACK事件触发。在这种情况下,网络继续从发送方向接收方交付报文段。因此TCP对这种丢包事件的行为,相比于超时指示的丢包,应当不那么剧烈:TCP将cwnd的值减半,并且当收到3个冗余ACK,将ssthresh的值记录为cwnd的值的一半。接下来进入快速恢复状态。

2.7.3 快速恢复

在快速恢复中,对于引起TCP进入快速恢复状态的缺失报文段,对收到的每个冗余ACK,cwnd的值增加一个MSS。最终,当对丢失报文段的一个ACK到达时,TCP在降低cwnd后进入拥塞避免状态。如果出现超时事件,快速恢复在执行如同在慢启动和拥塞避免中相同的动作后,迁移到慢启动状态:当丢包事件出现时,cwnd的值被设置为1个MSS,并且ssthresh的值设置为cwnd值的一半。

2.7.4 TCP拥塞控制整体回顾

忽略一条连接开始时初始的慢启动阶段,假定丢包由3个冗余的ACK而不是超时指示,TCP的拥塞控制是:每个RTT内cwnd线性增加1MSS,然后出现3个冗余ACK事件时cwnd减半。因此,TCP拥塞控制常常被称为加性增、乘性减(AIMD)拥塞控制方式。

2.7.5 对TCP吞吐量的宏观描述

只说结论:
一条连接的平均吞吐量≈(0.75×窗口长度)/RTT

2.7.6 公平性

只说结论:
当多条连接共享一个共同的瓶颈链路时,那些具有较小RTT的连接能够在链路空闲时更快地抢到可用带宽,因而将比那些具有较大RTT的连接享用更高的吞吐量。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值