网络应用是计算机网络存在的理由,一批早期的网络应用主要有电子邮件、远程访问、文件传输等,但是随着计算机网络的发展和人类无穷无尽的需求,越来越多的网络应用被开发出来,例如即时通讯和对等(P2P)文件共享,IP 电话、视频会议等。还有一些多方在线游戏被开发出来如《魔兽世界》等,可以说计算机网络是一切应用演变出来的基础。人要怀有一颗感恩的心,感谢这些前辈的努力,才让我们现在的生活如此丰富多彩。但是我们作为程序员,不仅要能够享受这些成果,还要知道为什么,这样生活才会和谐。
应用层协议原理
研发网络应用程序的核心是写出能够运行在不同的端系统和通过网络彼此通信的程序。例如,在网络应用程序中,有两个互相通信的不同程序:一个是运行在用户主机上的浏览器程序;另一个是运行在 Web 服务器主机上的 Web 服务器程序。
网络应用程序体系结构
网络应用程序的体系结构(application architecture)
主要有两种,一种是 客户-服务器体系结构(client-server architecture)
,在客户-服务器体系结构中,有一个持续打开,等待连接的主机称为服务器
,它服务于来自许多其他称为 客户
的主机请求。比如 Web 服务器总会等待来自浏览器(运行在客户主机上)的请求。注意这种客户-服务器体系结构中,客户之间是不会彼此交流信息的,它们只与相应的服务器进行通信。还有一点是服务器具有固定的 IP 地址。下图显示了这种体系结构
这种客户-服务器体系结构存在弊端,那就是有的时候服务器的响应跟不上客户请求速度的情况,鉴于此,这种体系结构需要经常配备数据中心(data center)
用来创建更强大的服务器。例如搜索引擎(谷歌、Bing和百度)
、互联网商店(亚马逊、e-Bay 和阿里巴巴)
、基于 Web 的电子邮件(Gmail 和 雅虎)
、社交网络(脸书、Instagram、推特和微信)
,就用了多个数据中心。
另外一种体系结构是 P2P体系结构(P2P architecture)
,相对于对数据中心有过多依赖的客户-服务器体系结构,P2P 体系结构则直接通过两台相连的主机直接通信,这些主机称为对等方
。典型的 P2P 体系结构的应用包括 文件共享(BitTorrent)
、下载器(迅雷)
、互联网电话和视频会议(Skype)
,下图显示了 P2P 体系结构图
P2P 体系结构最重要的一个特性就是它的自扩展性(self-scalability)
。例如,在一个 P2P 文件共享的应用中,尽管每个对等方都由于请求文件产生工作负载,但每个对等方通过向其他对等方分发文件也为系统增加服务器能力。
进程通信
我们上面说到了两种体系结构,一种是客户-服务器模式,一种是P2P 对等模式。我们都知道一个计算机允许同时运行多个应用程序,在我们看起来这些应用程序好像是同时运行的,那么它们之间是如何通信的呢?不可能存在同是一个母亲,兄弟俩不交流的情况吧。
用操作系统的术语来说,进行通信实际上是 进程(process)
而不是程序。一个进程可以被认为是运行在端系统中的程序。当多个进程运行在相同的端系统上,它们使用进程间的通信机制相互通信。进程间的通信规则由操作系统来确定。我们暂不关心运行在同一主机上不同应用程序是如何通信的,我们主要探讨的目标是不同端系统中两个进程是如何通信的。还是分为两种结构来探讨。
客户和服务器进程
网络应用程序由成对的进程
组成,这些进程通过网络相互发送报文。例如,在 Web 应用程序中,文件从一个对等方中的进程传输到另一个对等方中的进程。而在每对通信的进程中,都会有一对客户(client)
和 服务器(server)
存在。比如我们上面提到的 Web ,对于 Web 来说,浏览器是一个客户进程,而 Web 服务器是一台服务器进程。也许你也应该能猜到,在 P2P 体系结构中,一个进程能够扮演两种角色,既是客户又是服务器的情况。但是在实际通信的过程中,我们还是很容易区分的,我们通常通过下面这种方式进行区分。
在一对进程之间的通信会话场景中,发起通信(即在会话开始时发起与其他进程的联系)的进程称为
客户
,在会话开始时等待联系的被称为服务器
。
进程与计算机网络之间的接口
计算机是庞大且繁杂的,计算机网络也是,应用程序不可能只有一个进程组成,它同样是多个进程共同作用协商运行,然而,分布在多个端系统之间的进程是如何进行通信的呢?实际上,每个进程之间会有一个 套接字(socket)
的软件接口存在,套接字是应用程序的内部接口,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将 I/O 插入到网络中,并与网络中的其他应用程序进行通信。
通过一个实例来简单类比一下套接字和网络进程:进程可类比一座房子,而它的套接字相当于是房子的门,当一个进程想要与其他进程进行通信时,它会把报文推出门外,然后通过运输设备把报文运输到另外一座房子,通过门进入房子内部使用。
下图是一个通过套接字进行通信的流程图
从图可以看到,Socket 属于主机或者服务进程的内部接口,由应用程序开发人员进行控制,两台端系统之间进行通信会通过 TCP 的缓冲区经由网络传输到另一个端系统的 TCP 缓冲区,Socket 从 TCP 缓冲区读取报文供应用程序内部使用。
套接字是建立网络应用程序的可编程接口,因此套接字也被称为应用程序和网络之间的 应用程序编程接口(Application Programming Interface,API)
。应用程序开发人员可以控制套接字内部细节,但是无法控制运输层的传输,只能对运输层的传输协议进行选择,还可以对运输层的传输参数进行选择,比如最大缓存和最大报文长度等。
进程寻址
我们上面提到网络应用程序之间会相互发送报文,那么你怎么知道你应该向哪里发送报文呢?是不是存在某种机制能够让你知道你能够发到哪里?这就好比你要发送电子邮件,你写好了内容但是你不知道发发往哪里,所以这个时候必须要有一种知道对方地址的机制,这种机制能够辨明对方唯一的一个地址,这种地址就是 IP地址
。我们会在后面的文章中详细讨论 IP 地址的内容,目前只需要知道 IP 是一个32比特的量并且能够唯一标示互联网中任意一台主机的地址就可以了。
只知道 IP 地址是否就可以了呢?我们知道一台计算机可能会运行多个网络应用程序,那么如何确定是哪个网络应用程序接受发送过来的报文呢?所以这时候还需要知道网络应用程序的 端口号(port number)
。例如, Web 应用程序需要用 80 端口来标示,邮件服务器程序需要使用 25 来标示。
应用程序如何选择运输服务
我们知道应用程序是属于互联网四层协议的 应用层
协议,并且四层协议必须彼此协助共同完成工作。好了,这时候我们只有应用层协议,我们需要发送报文,我们如何发送报文呢?这就好比你知道目的地是哪里了,你该如何到达目的地呢?是走路,公交,地铁还是打车?
应用程序发送报文的交通工具
的选择也有很多,我们可以从 数据传输是否可靠、吞吐量、定时和安全性 来考虑,下面是你需要考虑的具体内容。
数据传输是否可靠
我们之前探讨过,分组在计算机网络中会存在丢包问题,丢包问题的严重性跟网络应用程序的性质有关,如果像是电子邮件、文件传输、远程主机、Web 文档传输的过程中出现问题,数据丢失可能会造成非常严重的后果。如果像是网络游戏,多人视频会议造成的影响可能比较小。鉴于此,数据传输的可靠性也是首先需要考虑的问题。因此,如果一个协议提供了这样的确保数据交付的服务,就认为提供了 可靠数据传输(reliable data transfer)
,能够忍受数据丢失的应用被称为 容忍丢失的应用(loss-tolerant application)
。
吞吐量
在之前的文章中我们引入了吞吐量的概念,吞吐量就是在网络应用中数据传输过程中,发送进程能够向接收进程交付比特的速率。具有吞吐量要求的应用程序被称为 带宽敏感的应用(bandwidth-sensitive application)
。带宽敏感的应用具有特定的吞吐量要求,而 弹性应用(elastic application)
能够根据当时可用的带宽或多或少地利用可供使用的吞吐量。
定时
定时是什么意思?定时能够确保网络中两个应用程序的收发是否能够在指定的时间内完成,这也是应用程序选择运输服务需要考虑的一个因素,这听起来很自然,你网络应用发送和接收数据包肯定要加以时间的概念,比如在游戏中,你一包数据迟迟发送不过去,对面都推塔了你还卡在半路上呢。
安全性
最后,选择运输协议一定要能够为应用程序提供一种或多种安全性服务。
因特网能够提供的运输服务
说完运输服务的选型,接下来该聊一聊因特网能够提供哪些服务了。实际上,因特网为应用程序提供了两种运输层的协议,即 UDP
和 TCP
,下面是一些网络应用的选择要求,可以根据需要来选择适合的运输层协议。
应用 | 数据丢失 | 带宽 | 时间敏感 |
文件传输 | 不能丢失 | 弹性 | 不敏感 |
电子邮件 | 不能丢失 | 弹性 | 不敏感 |
Web 文档 | 不能丢失 | 弹性 | 不敏感 |
因特网电话/视频会议 | 容忍丢失 | 弹性 | 敏感,100ms |
流式存储音频/视频 | 容忍丢失 | 弹性 | 敏感,几秒 |
交互式游戏 | 容忍丢失 | 弹性 | 是,100ms |
智能手机消息 | 不能丢失 | 弹性 | 无所谓 |
下面我们就来聊一聊这两种运输协议的应用场景
TCP
TCP
服务模型的特性主要有下面几种
- 面向连接的服务
在应用层数据报发送后, TCP 让客户端和服务器互相交换运输层控制信息。这个握手过程就是提醒客户端和服务器需要准备好接受数据报。握手阶段后,一个 TCP 连接(TCP Connection)
就建立了。这是一条全双工的连接,即连接双方的进程都可以在此连接上同时进行收发报文。当应用程序结束报文发送后,必须拆除连接。
- 可靠的数据传输
通信进程能够依靠 TCP,无差错、按适当顺序交付所有发送的数据。应用程序能够依靠 TCP 将相同的字节流交付给接收方的套接字,没有字节的丢失和冗余。
- 拥塞控制
TCP 的拥塞控制并不一定为通信进程带来直接好处,但能为因特网带来整体好处。当接收方和发送方之间的网络出现拥塞时,TCP 的拥塞控制会抑制发送进程(客户端或服务器),我们会在后面具体探讨拥塞控制
UDP
UDP
是一种轻量级的运输协议,它仅提供最小服务。UDP 是无连接的,因此在两个进程通信前没有握手过程。UDP 也不会保证报文是否传输到服务端,它就像是一个撒手掌柜。不仅如此,到达接收进程的报文也可能是乱序到达的。
下面是上表列出来的一些应用所选择的协议
应用 | 应用层协议 | 支撑的运输协议 |
电子邮件 | SMTP | TCP |
远程终端访问 | Telnet | TCP |
Web | HTTP | TCP |
文件传输 | FTP | TCP |
流式多媒体 | HTTP | TCP |
因特网电话 | SIP、RTP | TCP或UDP |
应用层协议
现在我们会探讨一些应用层协议,首先来认识一下什么是 应用层协议,应用层协议(application-layer protocol)
定义了运行在不同端系统上的应用进程如何相互传递报文。
应用层协议会定义
- 交换的报文类型,如请求报文和响应报文;
- 各种报文类型的语法,如报文中的各个字段公共详细描述;
- 字段的语义,即包含在字段中信息的含义;
- 进程何时、如何发送报文及对报文进行响应。
应用层协议分类
域名系统(Domain Name System, DNS)
:用于实现网络设备名字到 IP 地址映射的网络服务。文件传输协议(File Transfer Protocol,FTP)
:用于实现交互式文件传输功能。邮件传送协议(Simple Mail Transfer Protocol, SMTP)
:用于实现电子邮箱传送功能。超文本传输协议(HyperText Transfer Protocol,HTTP)
:用于实现 Web 服务。远程登录协议(Telnet)
:用于实现远程登录功能。
Web 和 HTTP
Web(World Wide Web)即全球广域网
,也就是 URL 为 www 开头的网络,它是 HTTP 协议的主要载体,是建立在 Internet 上的一种网络服务,我们一般讲的 Web ,其实就是指的 HTTP 协议,HTTP 协议作为 web 程序员必须要掌握并理解的一门协议,有必要好好了解一下。
超文本传输协议可以进行文字分割:超文本(Hypertext)、传输(Transfer)、协议(Protocol),它们之间的关系如下
按照范围的大小 协议 > 传输 > 超文本。下面就分别对这三个名次做一个解释。
什么是超文本
在互联网早期的时候,我们输入的信息只能保存在本地,无法和其他电脑进行交互。我们保存的信息通常都以文本
即简单字符的形式存在,文本是一种能够被计算机解析的有意义的二进制数据包。而随着互联网的高速发展,两台电脑之间能够进行数据的传输后,人们不满足只能在两台电脑之间传输文字,还想要传输图片、音频、视频,甚至点击文字或图片能够进行超链接
的跳转,那么文本的语义就被扩大了,这种语义扩大后的文本就被称为超文本(Hypertext)
。
什么是传输
那么我们上面说到,两台计算机之间会形成互联关系进行通信,我们存储的超文本会被解析成为二进制数据包,由传输载体(例如同轴电缆,电话线,光缆)负责把二进制数据包由计算机终端传输到另一个终端的过程(对终端的详细解释可以参考 你说你懂互联网,那这些你知道么?这篇文章)称为传输(transfer)
。
通常我们把传输数据包的一方称为请求方
,把接到二进制数据包的一方称为应答方
。请求方和应答方可以进行互换,请求方也可以作为应答方接受数据,应答方也可以作为请求方请求数据,它们之间的关系如下
如图所示,A 和 B 是两个不同的端系统,它们之间可以作为信息交换的载体存在,刚开始的时候是 A 作为请求方请求与 B 交换信息,B 作为响应的一方提供信息;随着时间的推移,B 也可以作为请求方请求 A 交换信息,那么 A 也可以作为响应方响应 B 请求的信息。