9.2. 分层协议¶
将一帧图像从摄像头发送到另一个城市的服务器,意味着要同时解决多个问题。电信号必须先穿过第一段线缆。线缆上的字节必须设法通过本地交换机。本地网络必须把消息交给位于它和互联网其余部分之间的设备。在旅途中幸存下来的数据包必须按顺序重新组装。接收方必须知道要把它们交给自己的哪个程序。而字节本身则必须表达两端都认同的含义。
试图在一段代码中解决所有这些问题将难以管理。标准的做法是把任务拆分为若干层。每一层解决一个明确定义的问题,并向上一层提供一个简单的服务。一个程序只与它正下方的那一层打交道;再下面的各层是不可见的。
网络协议栈的每一层解决一个问题,并向上一层交付一个干净的抽象。¶
9.2.1. 五个层次¶
下面的名称是本节其余部分所使用的。它们来自网络设计所围绕的标准模型。各层之间的确切边界有时是模糊的,但每一层所扮演的角色是稳定的。
物理层。 在同一根线缆或无线电上的两个设备之间传输比特。电压电平、光脉冲、射频调制。摄像头在这里的任务主要是插上正确的线缆或加入正确的无线网络;其余的工作由芯片完成。
链路层。 在共享一个本地网段的两个设备之间传输帧(小块字节)。它添加硬件地址,使每一帧能够定向到某个特定的邻居设备。以太网和 Wi-Fi 是摄像头在实际中遇到的两种链路技术。
网络层。 在互联网上任意两个设备之间传输数据包,而不仅仅是在同一本地网段上。它添加一个软件级地址,用以标识一台主机而不依赖于它连接在哪根线缆上,并添加一种路由机制,将数据包从一个本地网段跳转到下一个,直到抵达目的地。这是摄像头的 Python 代码开始有发言权的第一层。
传输层。 位于数据包之上,在两台主机上的程序之间提供传输,而不仅仅是主机本身之间。常见的有两种类型:一种传输有连接的、有序的字节流(大多数流量的主力),另一种传输彼此独立传送的自包含消息(当低开销比可靠性保证更重要时使用)。它添加端口号,使同一主机上的多个程序能够并行进行多个会话。
应用层。 传输层之上的一切:赋予字节含义的各种协议。Web 浏览器为加载页面所使用的协议——以及读者每天已经在用的几乎所有其他互联网服务背后的协议——都位于此处。本教程深入讲解传输层;这一层会有单独的后续章节专门介绍。
9.2.2. 运行时各层如何堆叠¶
当摄像头通过网络发送字节时,每一层都会在数据前面添加自己的头部,就像把一个信封套进另一个信封里一样:
应用程序的字节首先放入。
传输层用一个小头部将它们包裹起来,说明它们属于哪个程序(端口号)。
网络层用一个头部将这个整体再包裹起来,说明它们要发往哪台主机(软件级地址)。
链路层用一个头部将这个整体再包裹起来,说明接下来要把它们交给本地网段上的哪个设备(硬件地址)。
物理层将整个数据包转换为线缆上的比特。
在另一端,每一层剥离自己的头部并把其余部分向上交付。接收方应用程序拿回自己的字节,丝毫不知道网络层、链路层和物理层曾经存在过。
正是这种嵌套关系使得本教程采用自下而上的讲解方式。理解下面那一层所做的事情,会让上面那一层显得理所当然。最底下的两层各用一页介绍,因为从 Python 几乎没有什么可配置的。从网络层往上,随着 Python 的作用越来越大,讲解节奏会放慢。