本节书摘来华章计算机《计算机网络:自顶向下方法(原书第6版)》一书中的第2章 ,第2.1节,(美)James F.Kurose Keith W.Ross 著 陈 鸣 译 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
2.1 应用层协议原理
假定你对新型网络应用有了一些想法。也许这种应用将为人类提供一种伟大的服务,或者将使你的教授高兴,或者将带给你大量的财富,或者只是在开发中获得乐趣。无论你的动机是什么,我们现在考察一下如何将你的想法转变为一种真实世界的网络应用。
研发网络应用程序的核心是写出能够运行在不同的端系统和通过网络彼此通信的程序。例如,在Web应用程序中,有两个互相通信的不同的程序:一个是运行在用户主机(桌面机、膝上机、平板电脑、智能电话等)上的浏览器程序;另一个是运行在Web服务器主机上的Web服务器程序。另一个例子是P2P文件共享系统,在参与文件共享的社区中的每台主机中都有一个程序。在这种情况下,在各台主机中的这些程序可能都是类似的或相同的。
因此,当研发新应用程序时,你需要编写将在多台端系统上运行的软件。例如,该软件能够用C、Java或Python来编写。重要的是,你不需要写在网络核心设备如路由器或链路层交换机上运行的软件。即使你要为网络核心设备写应用程序软件,你也不能做到这一点。如我们在第1章所知,以及如图1-24所显示的那样,网络核心设备并不在应用层上起作用,而仅在较低层起作用,特别是位于网络层及下面层次。这种基本设计,也即将应用软件限制在端系统(如图2-1所示)的方法,促进了大量的网络应用程序的迅速研发和部署。
2.1.1 网络应用程序体系结构
当进行软件编码之前,应当对应用程序有一个宽泛的体系结构计划。记住应用程序的体系结构明显不同于网络的体系结构(例如在第1章中所讨论的5层因特网体系结构)。从应用程序研发者的角度看,网络体系结构是固定的,并为应用程序提供了特定的服务集合。在另一方面,应用程序体系结构(application architecture)由应用程序研发者设计,规定了如何在各种端系统上组织该应用程序。在选择应用程序体系结构时,应用程序研发者很可能利用现代网络应用程序中所使用的两种主流体系结构之一:客户-服务器体系结构或对等(P2P)体系结构。
在客户-服务器体系结构(client-server architecture)中,有一个总是打开的主机称为服务器,它服务于来自许多其他称为客户的主机的请求。一个经典的例子是Web应用程序,其中总是打开的Web服务器服务于来自浏览器(运行在客户主机上)的请求。当Web服务器接收到来自某客户对某对象的请求时,它向该客户发送所请求的对象作为响应。值得注意的是利用客户-服务器体系结构,客户相互之间不直接通信;例如,在Web应用中两个浏览器并不直接通信。客户-服务器体系结构的另一个特征是该服务器具有固定的、周知的地址,该地址称为IP地址(我们将很快讨论它)。因为该服务器具有固定的、周知的地址,并且因为该服务器总是打开的,客户总是能够通过向该服务器的IP地址发送分组来与其联系。具有客户-服务器体系结构的非常著名的应用程序包括Web、FTP、Telnet和电子邮件。图2-2a中显示了这种客户-服务器体系结构。
在一个客户-服务器应用中,常常会出现一台单独的服务器主机跟不上它所有客户请求的情况。例如,一个流行的社交网络站点如果仅有一台服务器来处理所有请求,将很快变得不堪重负。为此,配备大量主机的数据中心常被用于创建强大的虚拟服务器。最为流行的因特网服务——如搜索引擎(如谷歌和Bing)、因特网商务(如亚马逊和e-Bay)、基于Web的电子邮件(如Gmail和雅虎邮件)、社交网络(如脸谱和推特),就应用了一个或多个数据中心。如在1.3.3节中所讨论的那样,谷歌有分布于全世界的30~50个数据中心,这些数据中心共同处理搜索、YouTube、Gmail和其他服务。一个数据中心能够有数十万台服务器,它们必须要供电和维护。此外,服务提供商必须支付不断出现的互联和带宽费用,以发送和接收到达/来自数据中心的数据。
在一个P2P体系结构(P2P architecture)中,对位于数据中心的专用服务器有最小的(或者没有)依赖。相反,应用程序在间断连接的主机对之间使用直接通信,这些主机对被称为对等方。这些对等方并不为服务提供商所有,相反却为用户控制的桌面机和膝上机所有,大多数对等方驻留在家庭、大学和办公室。因为这种对等方通信不必通过专门的服务器,该体系结构被称为对等方到对等方的。许多目前流行的、流量密集型应用都是P2P体系结构的。这些应用包括文件共享(例如BitTorrent)、对等方协助下载加速器(例如迅雷)、因特网电话(例如Skype)和IPTV(例如“迅雷看看”和PPstream)。图2-2b中显示了P2P的体系结构。需要提及的是,某些应用具有混合的体系结构,它结合了客户-服务器和P2P的元素。例如,对于许多即时讯息应用而言,服务器被用于跟踪用户的IP地址,但用户到用户的报文在用户主机之间(无需通过中间服务器)直接发送。
P2P体系结构的最引人入胜的特性之一是它们的自扩展性(self-scalability)。例如,在一个P2P文件共享应用中,尽管每个对等方都由于请求文件产生工作量,但每个对等方通过向其他对等方分发文件也为系统增加服务能力。P2P体系结构也是成本有效的,因为它们通常不需要庞大的服务器基础设施和服务器带宽(这与具有数据中心的客户-服务器设计形成反差)。然而,未来P2P应用面临三个主要挑战:
- ISP友好。大多数住宅ISP(包括DSL和电缆ISP)已经受制于“非对称的”带宽应用,也就是说,下载比上载要多得多。但是P2P视频流和文件分发应用改变了从服务器到住宅ISP的上载流量,因而给ISP带来了巨大压力。未来P2P应用需要设计对ISP友好的模式[Xie 2008]。
- 安全性。因为它们的高度分布和开放特性,P2P应用给安全带来挑战[Doucer 2002;Yu 2006;Liang 2006;Naoumov 2006;Dhungel 2008;LeBlond 2011]。
- 激励。未来P2P应用的成功也取决于说服用户自愿向应用提供带宽、存储和计算资源,这对激励设计带来挑战[Feldman 2005;Piatek 2008;Aperjis 2008;Liu 2010]。
2.1.2 进程通信
在构建网络应用程序前,还需要对运行在多个端系统上的程序是如何互相通信的情况有一个基本了解。在操作系统的术语中,进行通信的实际上是进程(process)而不是程序。一个进程可以被认为是运行在端系统中的一个程序。当进程运行在相同的端系统上时,它们使用进程间通信机制相互通信。进程间通信的规则由端系统上的操作系统确定。而在本书中,我们不怎么关注同一台主机上的进程间的通信,而关注运行在不同端系统(可能具有不同的操作系统)上的进程间的通信。
在两个不同端系统上的进程,通过跨越计算机网络交换报文(message)而相互通信。发送进程生成并向网络中发送报文;接收进程接收这些报文并可能通过将报文发送回去进行响应。图2-1图示了进程是如何通过使用5层协议栈的应用层互相通信的。
1.客户和服务器进程
网络应用程序由成对的进程组成,这些进程通过网络相互发送报文。例如,在Web应用程序中,一个客户浏览器进程与一台Web服务器进程交换报文。在一个P2P文件共享系统中,文件从一个对等方中的进程传输到另一个对等方中的进程。对每对通信进程,我们通常将这两个进程之一标识为客户(client),而另一个进程标识为服务器(server)。对于Web而言,浏览器是一个客户进程,Web服务器是一台服务器进程。对于P2P文件共享,下载文件的对等方标识为客户,上载文件的对等方标识为服务器。
你或许已经观察到,如在P2P文件共享的某些应用中,一个进程能够既是客户又是服务器。在P2P文件共享系统中,一个进程的确既能上载文件又能下载文件。无论如何,在任何给定的一对进程之间的通信会话场景中,我们仍能将一个进程标识为客户,另一个进程标识为服务器。我们定义客户和服务器进程如下:
在给定的一对进程之间的通信会话场景中,发起通信(即在该会话开始时发起与其他进程的联系)的进程被标识为客户,在会话开始时等待联系的进程是服务器。
在Web中,一个浏览器进程向一台Web服务器进程发起联系,因此该浏览器进程是客户,而该Web服务器进程是服务器。在P2P文件共享中,当对等方A请求对等方B发送一个特定的文件时,在这个特定的通信会话中对等方A是客户,而对等方B是服务器。在不致混淆的情况下,我们有时也使用术语“应用程序的客户端和服务器端”。在本章的结尾,我们将逐步讲解网络应用程序的客户端和服务器端的简单代码。
2.进程与计算机网络之间的接口
如上所述,多数应用程序是由通信进程对组成,每对中的两个进程互相发送报文。从一个进程向另一个进程发送的报文必须通过下面的网络。进程通过一个称为套接字(socket)的软件接口向网络发送报文和从网络接收报文。我们考虑一个类比来帮助我们理解进程和套接字。进程可类比于一座房子,而它的套接字可以类比于它的门。当一个进程想向位于另外一台主机上的另一个进程发送报文时,它把报文推出该门(套接字)。该发送进程假定该门到另外一侧之间有运输的基础设施,该设施将把报文传送到目的进程的门口。一旦该报文抵达目的主机,它通过接收进程的门(套接字)传递,然后接收进程对该报文进行处理。
图2-3显示了两个经过因特网通信的进程之间的套接字通信(图2-3中假定由该进程使用的下面运输层协议是因特网的TCP协议)。如该图所示,套接字是同一台主机内应用层与运输层之间的接口。由于该套接字是建立网络应用程序的可编程接口,因此套接字也称为应用程序和网络之间的应用程序编程接口(Application Programming Interface,API)。应用程序开发者可以控制套接字在应用层端的一切,但是对该套接字的运输层端几乎没有控制权。应用程序开发者对于运输层的控制仅限于:①选择运输层协议;②也许能设定几个运输层参数,如最大缓存和最大报文段长度等(将在第3章中涉及)。一旦应用程序开发者选择了一个运输层协议(如果可供选择的话),则应用程序就建立在由该协议提供的运输层服务之上。我们将在2.7节中对套接字进行更为详细的探讨。
3.进程寻址
为了向特定目的地发送邮政邮件,目的地需要有一个地址。类似地,在一台主机上运行的进程为了向在另一台主机上运行的进程发送分组,接收进程需要有一个地址。为了标识该接收进程,需要定义两种信息:①主机的地址;②定义在目的主机中的接收进程的标识符。
在因特网中,主机由其IP地址(IP address)标识。我们将在第4章中非常详细地讨论IP地址。此时,我们只要知道IP地址是一个32比特的量且它能够唯一地标识该主机就够了。除了知道报文送往目的地的主机地址外,发送进程还必须指定运行在接收主机上的接收进程(更具体地说,接收套接字)。因为一般而言一台主机能够运行许多网络应用,这些信息是需要的。目的地端口号(port number)用于这个目的。已经给流行的应用分配了特定的端口号。例如,Web服务器用端口号80来标识。邮件服务器进程(使用SMTP协议)用端口号25来标识。用于所有因特网标准协议的周知端口号的列表能够在http://www.iana.org处找到。我们将在第3章中详细学习端口号。
2.1.3 可供应用程序使用的运输服务
前面讲过套接字是应用程序进程和运输层协议之间的接口。在发送端的应用程序将报文推进该套接字。在该套接字的另一侧,运输层协议负责使该报文进入接收进程的套接字。
包括因特网在内的很多网络提供了不止一种运输层协议。当开发一个应用时,必须选择一种可用的运输层协议。如何做出这种选择呢?最可能的方式是,通过研究这些可用的运输层协议所提供的服务,选择一个最能为你的应用需求提供恰当服务的协议。这种情况类似于在两个城市间旅行时选择飞机还是火车作为交通工具。你必须选择一种或另一种,而且每种运输模式为你提供不同的服务(例如,火车可以直到市区上客和下客,而飞机提供了更短的旅行时间)。
一个运输层协议能够为调用它的应用程序提供什么样的服务呢?我们大体能够从四个方面对应用程序服务要求进行分类:可靠数据传输、吞吐量、定时和安全性。
1.可靠数据传输
如第1章讨论的那样,分组在计算机网络中可能丢失。例如,分组能够使路由器中的缓存溢出,或者当分组中的某些比特损坏后可能被丢弃。像电子邮件、文件传输、远程主机访问、Web文档传输以及金融应用等这样的应用,数据丢失可能会造成灾难性的后果(在后一种情况下,无论对银行或对顾客都是如此!)。因此,为了支持这些应用,必须做一些工作以确保由应用程序的一端发送的数据正确、完全地交付给该应用程序的另一端。如果一个协议提供了这样的确保数据交付服务,就认为提供了可靠数据传输(reliable data transfer)。运输层协议能够潜在地向应用程序提供的一个重要服务是进程到进程的可靠数据传输。当一个运输协议提供这种服务时,发送进程只要将其数据传递进套接字,就可以完全相信该数据将能无差错地到达接收进程。
当一个运输层协议不提供可靠数据传输时,由发送进程发送的某些数据可能不能够到达接收进程。这可能能被容忍丢失的应用(loss-tolerant application)所接受,最值得注意的是多媒体应用,如交谈式音频/视频,它们能够承受一定量的数据丢失。在这些多媒体应用中,丢失的数据引起播放的音频/视频出现小干扰,而不是致命的损伤。
2.吞吐量
在第1章中我们引入了可用吞吐量的概念,在沿着一条网络路径上的两个进程之间的通信会话场景中,可用吞吐量就是发送进程能够向接收进程交付比特的速率。因为其他会话将共享沿着该网络路径的带宽,并且因为这些会话将会到达和离开,该可用吞吐量将随时间波动。这些观察导致另一种自然的服务,即运输层协议能够以某种特定的速率提供确保的可用吞吐量。使用这种服务,该应用程序能够请求r比特/秒的确保吞吐量,并且该运输协议能够确保可用吞吐量总是为至少r比特/秒。这样的确保吞吐量的服务将对许多应用程序有吸引力。例如,如果因特网电话应用程序对语音以32kbps的速率进行编码,那么它也必须以这个速率向网络发送数据,并向接收应用程序交付数据。如果运输协议不能提供这种吞吐量,该应用程序或以较低速率进行编码(并且接收足够的吞吐量以维持这种较低的编码速率),或它可能必须放弃发送,这是因为对于这种因特网电话应用而言,接收所需吞吐量的一半是几乎没有或根本没有用处的。具有吞吐量要求的应用程序被称为带宽敏感的应用(bandwidth-sensitive application)。许多当前的多媒体应用是带宽敏感的,尽管某些多媒体应用程序可能采用自适应编码技术对数字语音或视频以与当前可用带宽相匹配的速率进行编码。
带宽敏感的应用具有特定的吞吐量要求,而弹性应用(elastic application)能够根据情况或多或少地利用可供使用的吞吐量。电子邮件、文件传输以及Web传送都属于弹性应用。当然,吞吐量是越多越好。有一句格言说得好,钱越多越好,人越瘦越美,我们永远不会嫌吞吐量太多的!
3.定时
运输层协议也能提供定时保证。如同具有吞吐量保证那样,定时保证能够以多种形式实现。一个保证的例子如:发送方注入进套接字中的每个比特到达接收方的套接字不迟于100ms。这种服务将对交互式实时应用程序有吸引力,如因特网电话、虚拟环境、电话会议和多方游戏,所有这些服务为了有效性而要求数据交付有严格的时间限制(参见第7章,[Gauthier 1999;Ramjee 1994])。例如,在因特网电话中,较长的时延会导致会话中出现不自然的停顿;在多方游戏和虚拟互动环境中,在做出动作并看到来自环境(如来自位于端到端连接中另一端点的玩家)的响应之间,较长的时延使得它失去真实感。对于非实时的应用,较低的时延总比较高的时延好,但对端到端的时延没有严格的约束。
4.安全性
最后,运输协议能够为应用程序提供一种或多种安全性服务。例如,在发送主机中,运输协议能够加密由发送进程传输的所有数据,在接收主机中,运输层协议能够在将数据交付给接收进程之前解密这些数据。这种服务将在发送和接收进程之间提供机密性,以防该数据以某种方式在这两个进程之间被观察到。运输协议还能提供除了机密性以外的其他安全性服务,包括数据完整性和端点鉴别,我们将在第8章中详细讨论这些主题。
2.1.4 因特网提供的运输服务
至此,我们已经考虑了计算机网络能够一般性地提供的运输服务。现在我们要更为具体地考察由因特网提供的运输服务类型。因特网(更一般的是TCP/IP网络)为应用程序提供两个运输层协议,即UDP和TCP。当你(作为一个软件开发者)为因特网创建一个新的应用时,首先要做出的决定是,选择UDP还是选择TCP。每个协议为调用它们的应用程序提供了不同的服务集合。图2-4显示了某些所选的应用程序的服务要求。
应用数据丢失带宽时间敏感文件传输不能丢失弹性不电子邮件不能丢失弹性不Web文档不能丢失弹性(几kbps)不因特网电话/视频会议容忍丢失音频(几kbps~1Mbps)视频(10kbps~5Mbps)是,100ms存储音频/视频容忍丢失同上是,几秒交互式游戏容忍丢失几kbps~10kbps是,100ms即时讯息不能丢失弹性是和不是
1.TCP服务
TCP服务模型包括面向连接服务和可靠数据传输服务。当某个应用程序调用TCP作为其运输协议时,该应用程序就能获得来自TCP的这两种服务。
- 面向连接的服务:在应用层数据报文开始流动之前,TCP让客户和服务器互相交换运输层控制信息。这个所谓的握手过程提示客户和服务器,使它们为大量分组的到来做好准备。在握手阶段后,一个TCP连接(TCP connection)就在两个进程的套接字之间建立了。这条连接是全双工的,即连接双方的进程可以在此连接上同时进行报文收发。当应用程序结束报文发送时,必须拆除该连接。在第3章中我们将详细讨论面向连接的服务,并分析它是如何实现的。
- 可靠的数据传送服务:通信进程能够依靠TCP,无差错、按适当顺序交付所有发送的数据。当应用程序的一端将字节流传进套接字时,它能够依靠TCP将相同的字节流交付给接收方的套接字,而没有字节的丢失和冗余。
TCP协议还具有拥塞控制机制,这种服务不一定能为通信进程带来直接好处,但能为因特网带来整体好处。当发送方和接收方之间的网络出现拥塞时,TCP的拥塞控制机制会抑制发送进程(客户或服务器)。如我们将在第3章中所见,TCP拥塞控制也试图限制每个TCP连接,使它们达到公平共享网络带宽的目的。
2.UDP服务
UDP是一种不提供不必要服务的轻量级运输协议,它仅提供最小服务。UDP是无连接的,因此在两个进程通信前没有握手过程。UDP协议提供一种不可靠数据传送服务,也就是说,当进程将一个报文发送进UDP套接字时,UDP协议并不保证该报文将到达接收进程。不仅如此,到达接收进程的报文也可能是乱序到达的。
UDP没有包括拥塞控制机制,所以UDP的发送端可以用它选定的任何速率向其下层(网络层)注入数据。(然而,值得注意的是实际端到端吞吐量可能小于这种速率,这可能是因为中间链路的带宽受限或因为拥塞而造成的。)
3.因特网运输协议所不提供的服务
我们已经从4个方面组织了运输协议服务:可靠数据传输、吞吐量、定时和安全性。TCP和UDP提供了这些服务中的哪些呢?我们已经注意到TCP提供了可靠的端到端数据传送。并且我们也知道TCP在应用层可以很容易地用SSL来加强以提供安全服务。但在我们对TCP和UDP的简要描述中,明显地缺少了对吞吐量或定时保证的讨论,即这些服务目前的因特网运输协议并没有提供。这是否意味着诸如因特网电话这样的时间敏感应用不能运行在今天的因特网上呢?答案显然是否定的,因为在因特网上运行时间敏感应用已经有多年了。这些应用经常工作得相当好,因为它们已经被设计成尽最大可能对付这种保证的缺乏。我们将在第7章中研究几种设计技巧。无论如何,在时延过大或端到端吞吐量受限时,好的设计也是有限制的。总之,今天的因特网通常能够为时间敏感应用提供满意的服务,但它不能提供任何定时或带宽保证。
图2-5指出了一些流行的因特网应用所使用的运输协议。可以看到,电子邮件、远程终端访问、Web、文件传输都使用了TCP。这些应用选择TCP的最主要原因是TCP提供了可靠数据传输服务,确保所有数据最终到达目的地。因为因特网电话应用(如Skype)通常能够容忍某些丢失但要求达到一定的最小速率才能有效工作,所以因特网电话应用的开发者通常愿意将该应用运行在UDP上,从而设法避开TCP的拥塞控制机制和分组开销。但因为许多防火墙被配置成阻挡(大多数类型的)UDP流量,所以因特网电话应用通常设计成如果UDP通信失败就使用TCP作为备份。
2.1.5 应用层协议
我们刚刚学习了通过把报文发送进套接字使网络进程间实现相互通信。但是如何构造这些报文?在这些报文中的各个字段的含义是什么?进程何时发送这些报文?这些问题将我们带进应用层协议的范围。应用层协议(application-layer protocol)定义了运行在不同端系统上的应用程序进程如何相互传递报文。特别是应用层协议定义了:
- 交换的报文类型,例如请求报文和响应报文。
- 各种报文类型的语法,如报文中的各个字段及这些字段是如何描述的。
- 字段的语义,即这些字段中包含的信息的含义。
- 一个进程何时以及如何发送报文,对报文进行响应的规则。
有些应用层协议是由RFC文档定义的,因此它们位于公共域中。例如,Web的应用层协议HTTP(超文本传输协议[RFC 2616])就作为一个RFC可供使用。如果浏览器开发者遵从HTTP RFC规则,所开发出的浏览器就能访问任何遵从该文档标准的Web服务器并获取相应Web页面。还有很多别的应用层协议是专用的,有意不为公共域使用。例如,Skype使用了专用的应用层协议。
区分网络应用和应用层协议是很重要的。应用层协议只是网络应用的一部分(尽管从我们的角度看,它是应用非常重要的一部分)。我们来看一些例子。Web是一种客户-服务器应用,它允许客户按照需求从Web服务器获得文档。该Web应用有很多组成部分,包括文档格式的标准(即HTML)、Web浏览器(如Firefox和Microsoft Internet Explorer)、Web服务器(如Apache、Microsoft服务器程序),以及一个应用层协议。Web的应用层协议是HTTP,它定义了在浏览器和Web服务器之间传输的报文格式和序列。因此,HTTP只是Web应用的一个部分(尽管是重要部分)。举另外一个例子,因特网电子邮件应用也有很多组成部分,包括能容纳用户邮箱的邮件服务器、允许用户读取和生成邮件的邮件客户程序(如Microsoft Outlook)、定义电子邮件报文结构的标准、定义报文如何在服务器之间以及如何在服务器与邮件客户程序之间传递的应用层协议、定义如何对报文首部的内容进行解释的应用层协议。用于电子邮件的主要应用层协议就是SMTP(简单邮件传输协议[RFC5321])。因此,电子邮件的首要应用层协议SMTP也只是电子邮件应用的一个部分(尽管是重要部分)。
2.1.6 本书涉及的网络应用
每天都有新的公共域或者专用域因特网应用被开发出来。我们不愿像百科全书一样涉及大量的因特网应用,而是选择其中几种重要而流行的应用加以关注。在本章中我们详细讨论5种重要的应用:Web、文件传输、电子邮件、目录服务和P2P。我们首先讨论Web应用,不仅因为它是极为流行的应用,而且因为它的应用层协议HTTP相对比较简单并且易于理解。讨论完Web,我们简要地讨论FTP,因为它与HTTP形成了很好的对照。我们接下来讨论电子邮件应用,这是因特网上最早的招人喜爱的应用程序。说电子邮件比Web更复杂,是因为它使用了多个而不是一个应用层协议。在电子邮件之后,我们讨论DNS,它为因特网提供目录服务。大多数用户不直接与DNS打交道,而是通过其他的应用(包括Web、文件传输和电子邮件)间接使用它。DNS很好地说明了一种核心的网络功能(网络名字到网络地址的转换)是怎样在因特网的应用层实现的。本章最后我们讨论了几种P2P应用,重点关注文件共享应用、分布式查找服务。在第7章中,我们将涉及多媒体应用,包括流式视频和IP电话。