在介绍完计算机基础知识和 TCP/IP 协议簇的基础概念之后,相信读者对计算机网络有了初步的认识,那么下面我们就要对不同的协议层进行分类介绍了,我们选用从应用层产生数据开始,逐步下探至数据链路层,因为这种介绍对读者来说更容易接纳,吸收程度更好。
一般情况下,用户不会在意网络应用程序是按照怎样的机制运行的,用户也不会关心它们是如何产生数据的,如何经过协议栈层层包装把数据发出去的,但是我们是程序员,必须要专业一点,势必要掌握好理论知识然后在合适的时间讲出来好让别人认为我们是大佬 :)
应用层位于 TCP/IP 模型的最上层,同时应用层也对应 OSI 标准模型的第 5、6、7层,也就是会话层、表现层、应用层。
应用层概念
现如今,越来越多的应用程序通过计算机网络实现相互通信,这些应用包括 Web 浏览器、远程登录、电子邮件、文件传输、文件下载等,而这些应用的日常使用势必要遵循某种协议和规范,应用层协议正是进行这些行为活动的规则和标准。
简单来说,应用层就是规定应用程序在进行通信时所遵循的协议。
应用层协议的定义
应用层协议定义了在不同端系统上应用程序是如何相互传输报文的。一般来说,应用层协议会规定如下内容:
-
交换的报文类型:交换的是请求报文还是响应报文。
-
报文字段的解释:对报文中各个字段的详细描述。
-
报文字段的语义:报文各个字段的含义是什么。
-
报文交换时间、方式:程序何时、以什么方式发送报文以及响应。
直白一点来说,应用层只是产生和使用数据的逻辑层,在这一层次我们并不会关心它们是如何发送数据的以及数据发到哪里。应用层有两种层次结构:
应用层体系结构
应用层体系结构定义了应用层端系统之间数据交换的方式,一般来说,主流的体系结构有两种:
-
客户-服务器体系结构 - CS 结构 (client-server architecture)
-
对等体系结构 - P2P 结构 (P2P architecture)
在客户-服务器体系结构中,分为请求方和服务方。有一个总是打开的主机称为服务端 (Server),它向客户端 (client) 提供服务。客户端会发送请求给服务端,服务端会根据客户端的请求做出响应。举一个简单的例子:我今天下馆子去,找到了一个饭店,这时候会有一个服务员热情接见我,我看完菜单给服务员说我想吃猪肉,这个"我想吃猪肉"就是请求,然后服务员报以热情的微笑并扇了我一巴掌,说:"我们这是清真馆",这个服务员对我笑并扇了我一巴掌然后对我说了句话,就是响应。
我们最常见的服务端就是 Web 服务器,Web 服务器提供于来自浏览器的请求。我们日常访问百度、谷歌,其实就是在访问它们的 Web 服务器。
一般常见的 Web 服务器主要有Apache、IIS、Jboss、Tomcat、WebSphere、WebLogic 等。
当 Web 服务器通过浏览器接收到用户请求后,它会经过一系列的处理把信息或者页面等通过浏览器呈现给用户,这种模式就是客户 - 服务器模式。
这里有两点需要注意
-
在客户 - 服务器模式下,通常客户端彼此之间是并不互相通信的。
-
服务器通常具有固定的、周知的 IP 地址可以提供访问。
客户 - 服务器模式通常会出现随着客户数量的急剧增加导致单台服务器无法满足大量请求的情况。为此,通常需要配备大量的数据中心 (data center),用来跟踪所有的用户请求。
与此相反,P2P 对等体系结构对这种数据中心的依赖性很低,因为在 P2P 体系结构中,应用程序在两个主机之间直接通信,这些主机被称为对等方,与有中心服务器的中央网络系统不同,对等网络的每个用户端既是一个请求方也是一个服务提供方。常见的 P2P 体系结构的应用有文件共享、视频会议、网络电话等。举个例子:毕业了很多大学生都有许多个人物品来不及处理,这时候大家会搞一个跳蚤市场,来彼此出售、交换一些个人物品,这里面每个人既是请求方,同时也是服务提供方。
说到跳蚤市场,啰嗦两句,一般这种跳蚤市场有很多好东西,好用不贵,而且卖的东西种类繁多,物品齐全,性价比贼高,懂得都懂。
P2P 一个最大的特点就是扩展性 (self-scalability),因为 P2P 网络的一个重要的目标就是让所有的客户端都能提供资源、获取资源,共享带宽,存储空间等。因此,当有更多节点加入且对系统请求增多,整个系统的容量也增大。这是具有一组固定服务器的客户 - 服务器结构不具备的,这也就是 P2P 的优势。
在了解完上述这两种结构之后,我们把关注点放在这两种体系结构下,各个端系统之间是如何进行通信的。
进程通信
我们上面说到了两种体系结构,一种是客户 - 服务器 CS 模式,一种是 P2P 对等模式。我们都知道一个计算机允许同时运行多个应用程序,在我们看起来这些应用程序好像是同时运行的,那么它们之间是如何通信的呢?
从操作系统的角度上来说,进行通信的实际上是进程 (process) 而不是程序。我们一般所讲的是进程通信,但是没人说程序通信的。进程是一类程序,但是程序并不特指的是进程。一个进程可以被认为是运行在端系统中的程序。当多个进程运行在相同的端系统上时,它们使用进程间的通信机制相互通信。进程间的通信规则由操作系统来确定。
进程与计算机网络之间的接口
计算机是庞大且繁杂的,计算机网络也是,应用程序不可能只有一个进程组成,它同样是多个进程共同作用协商运行,那么分布在多个端系统之间的进程是如何进行通信的呢?实际上,每个进程中会有一个套接字 (socket)的,它其实是一个软件接口,套接字也是应用程序的内部接口,应用程序可以通过它发送或接收数据,同时也可以对其进行像对文件一样的打开、读写和关闭等操作。
举个例子来简单类比一下套接字和网络进程:进程可类比一座房子,而它的套接字相当于是房子的门,当一个进程想要与其他进程进行通信时,它会把报文推出门外,然后通过运输设备把报文运输到另外一座房子,通过门进入房子内部,提供给其他进程使用。
下图是一个通过套接字进行通信的示意图。
从上图可以看到,Socket 属于主机或者服务进程的内部接口,由应用程序开发人员进行控制,两台端系统之间进行通信会通过 TCP 缓冲区经由网络传输到另一个端系统的 TCP 缓冲区,Socket 从 TCP 缓冲区读取报文供应用程序内部使用。
套接字是建立网络应用程序的可编程接口,因此套接字也被称为应用程序和网络之间的应用程序编程接口( Application Programming Interface,API )。应用程序开发人员可以控制套接字内部细节,但是无法控制运输层的传输,只能对运输层的传输协议进行选择,还可以对运输层的传输参数进行选择,比如最大缓存和最大报文长度等。
关于更多 Socket 的内容,我们会在后面进行讨论。
进程寻址
我们上面提到网络应用程序之间会相互发送报文,那么它是如何知道自己应该向哪个应用进程发送呢?是不是存在某种机制能够让它知道发到哪里?这就好比你要发送电子邮件,你写好了内容但是你不知道给谁发,所以这个时候必须要有一种知道对方地址的机制,并且能够辨明对方唯一的地址,这个地址就是IP 地址。我们会在后面的内容中详细讨论 IP 地址的内容,目前只需要知道 IP 地址是一个 32 比特的数据并且能够唯一标示互联网中任意一台主机的地址就可以了。
只知道 IP 地址是否就可以了呢?当然不行,举个例子:IP 地址就相当于是你在地图上的唯一坐标,比如说是河北省石家庄市xx小区xx栋xx层xx号,可以具体到门牌号,但是你家里可能会有多个人,你到底要给家里的谁发送信息?这个需要明确下,所以上面的门牌号,就相当于是 IP 地址,你要给家里的谁发送消息,这个谁就是端口号。例如,Web 应用程序需要用 80 端口来标示,邮件服务器程序需要使用 25 来标示,这个谁就是 80 或者 25 端口。
应用程序如何选择运输服务
我们知道应用程序是按照应用层协议的标准传输数据的,应用程序只是起到一个生产数据和应用数据的程序,那么我们该如何发送报文呢?这就好比你知道目的地是哪里了,你应该选择哪种交通工具?是走路,公交,地铁还是打车?
应用程序发送报文的交通工具的选择也有很多,我们可以从下面这几个方面来进行考量。
- 数据传输是否可靠
分组在计算机网络中会存在丢包问题,丢包问题的严重性和网络协议的性质有关,如果像是电子邮件、文件传输、远程主机、Web 文档传输的过程中出现问题,数据丢失可能会造成非常严重的后果。如果像是网络游戏,多人视频会议造成的影响可能比较小。鉴于此,数据传输的可靠性也是首先需要考虑的问题。因此,如果协议提供了这样的确保数据交付的服务,就认为提供了可靠数据传输,能够忍受数据丢失的应用被称为容忍丢失的应用。
- 吞吐量
吞吐量就是在数据传输过程中,发送进程能够向接收进程交付比特的速率。具有吞吐量要求的应用程序被称为带宽敏感的应用 。带宽敏感的应用具有特定的吞吐量要求,而弹性应用能够根据当时可用的带宽或多或少地利用可供使用的吞吐量。
- 定时
定时能够确保网络中两个应用程序的收发能否在指定的时间内完成,这也是应用程序选择运输服务需要考虑的一个因素。比如在游戏中,你一包数据迟迟发送不过去,对面都推塔了你还卡在半路上呢。
- 安全性
最后,选择运输协议一定要能够为应用程序提供一种或多种安全性服务,这个也是非常重要的。
因特网能够提供的运输服务
说完运输服务的选型,接下来该聊一聊因特网能够提供哪些服务了。实际上,因特网为应用程序提供了两种运输层的协议,即 UDP 和 TCP,下面是一些网络应用的选择要求,可以根据需要来选择适合的运输层协议。
下面我们就来聊一聊这两种运输协议的应用场景:
TCP
TCP 服务模型的特性主要有下面几种:
- 面向连接的服务
在应用层数据报发送后, TCP 会让客户端和服务器互相交换运输层控制信息,交换信息前需要先建立一条连接通道,这个建立连接的过程就是握手。这个握手过程就是提醒客户端和服务器,你们准备好接收数据了吗?握手完成后,一个TCP 连接 (TCP Connection) 就此建立。TCP 连接是一条全双工的,全双工的意思是连接双方的进程都可以在此连接上同时进行收发报文。当应用程序结束报文发送后,必须断开连接。
- 可靠的数据传输
通信进程能够依靠 TCP 无差错、按适当顺序交付所有发送的数据。应用程序能够依靠 TCP 将相同的字节流交付给接收方的套接字,没有字节的丢失和冗余。
- 拥塞控制
当接收方和发送方之间的网络出现拥塞时,TCP 的拥塞控制会抑制发送进程(客户端或服务器),等到网络状态恢复正常后再继续发送。TCP 的拥塞控制并不一定为通信进程带来直接好处,但能为因特网带来整体好处。我们会在后面具体探讨拥塞控制。
UDP
UDP 是一种轻量级的传输协议,UDP 是无连接的,因此使用 UDP 协议不需要经过握手过程,直接发就行。UDP 也不会保证报文是否传输到服务端,它就像是一个撒手掌柜。不仅如此,到达接收进程的报文也可能是乱序到达的。但是 UDP 的传输速率非常快,非常适合大多数互联网应用。
下面是上表列出来的一些应用所选择的协议: