笔记 | 【Linux网络】网络为什么要分层?从协议、OSI 到 TCP/IP,一次搭起网络通信整体框架(学习笔记)

今天翻到一篇不错的技术分享,看完之后自己也琢磨了一下,把思路梳理记录下来。

🔥个人主页:爱和冰阔乐 📚专栏传送门:《数据结构与算法》 、C++、 《Linux操作系统》 🐶学方向:C++方向学爱好者 ⭐人生格言:得知坦然 ,失之淡然

🏠博主简介

文章目录

二、协议:通信双方共同遵守的约定 三、协议为什么要分层 四、OSI 七层模型五、TCP/IP 五层模型 六、为什么需要 TCP/IP 协议栈 七、协议在代码中是什么样的 八、两种观察网络通信的视角九、这一阶段容易混淆的几个问题 总结

前言

前面学进程、线程时,咱们研究的对象基本都在一台主机内部。到了网络部分,问题变成了:一台主机上的进程,怎样把数据交给另一台主机上的进程?

只给两台计算机接一根网线还不够。距离一旦拉长,数据可能丢失,目标主机需要定位,沿途还要经过交换机、路由器等设备。即使数据已经到达目标主机,操作系统还得判断它究竟属于浏览器、QQ,还是其他进程。

这些问题需要一整套分层协议共同处理。本篇先从网络的发展讲起,再把协议、协议分层、OSI 模型和 TCP/IP 模型串起来。把这条主线理顺,后面再学习 IP、TCP、UDP 和 Socket,就不会只剩下一堆零散名词。

一、计算机网络为什么会出现

1.1 从独立计算机到网络互联

早期的计算机以独立模式工作。每台机器只处理自己的任务,机器之间没有直接的数据交换。

但是计算机终究是人使用的工具。人需要协作,计算机保存的数据也就需要交换。两台计算机连接起来之后,文件、计算结果和设备资源都可以在机器之间流动,网络便有了最基本的形态。

最初的网络通常只服务于学校、实验室或企业内部。连接的主机增多之后,不能再简单地把所有机器一根根直连,于是交换机、路由器等设备逐步进入网络。

1.2 局域网和广域网

在一个范围较小的区域内,把多台主机连接起来形成的网络,一般称为局域网(LAN)。学校机房、公司办公网和家庭网络,都可以看成局域网。

当不同地区的局域网继续互联,网络的范围会扩大到城市、国家,甚至全球,这时便形成了广域网(WAN)。

局域网和广域网是相对概念,不是按照某个固定半径硬切出来的。站在学校机房内部看,校园网已经很大;站在全国骨干网的角度看,它仍然只是一个接入网络。

网络从局部发展到整体,也带动了一整套基础设施的出现:

  • 网线、光纤和无线电负责传递信号;
  • 交换机负责局域网内的数据转发;
  • 路由器负责连接不同网络并选择转发路径;
  • 运营商建设基站、骨干网和机房,让分散的网络能接入互联网;
  • 互联网公司在这些基础设施上提供搜索、通信、购物和视频等服务。
互联网由大量硬件、软件、线路和标准共同组成,不属于某一家公司的单独产品。

二、协议:通信双方共同遵守的约定

2.1 为什么有连接还不够

两台计算机连上网线,只能说明物理通道已经存在,并不代表它们一定能正确交流。

计算机在介质上传递的是光信号、电信号或无线电信号。信号最终要解释成 0 和 1,而这些二进制数据又要被解释成具体消息。发送方怎样组织数据,接收方就必须怎样理解,否则双方见到的只是一串没有意义的比特。

协议就是通信双方事先做好的约定。 它至少要说明:

1. 数据按照什么格式组织;
2. 每个字段表示什么;
3. 消息按照什么顺序交互;
4. 出现异常时应该怎样处理。

生活中也有类似情况。两个人说同一种语言,才能直接交流;打电话时,还要遵守“拨号、接通、讲话、挂断”这一套过程。只约定一句“咱们要通信”没有意义,真正可执行的约定必须足够具体。

2.2 为什么需要统一标准

网络中的主机来自不同厂商,操作系统也不相同,网卡和交换机更不可能只由一家生产。如果每个厂商都使用自己的格式,那么设备只能和自家产品通信,互联网也就无法形成。

于是,网络协议通常由标准组织制定,再由不同系统和设备按照标准实现。咱们经常遇到的组织包括:

  • ISO:提出 OSI 开放系统互连参考模型;
  • IEEE:制定大量局域网标准,例如 IEEE 802 系列;
  • IETF:通过 RFC 推动互联网协议的发展,TCP/IP 协议族中的不少规范都来自这里;
  • ITU-T:负责电信领域的国际标准。
标准只规定“应该怎样做”,并不替某个操作系统写代码。Linux、Windows 和其他系统可以采用不同的内部实现,只要对外行为符合协议,彼此就能通信。

这也是标准的价值:内部实现可以不同,外部接口和数据格式必须一致。

连接解决“能不能传”,协议解决“双方能不能按照相同规则理解数据”。

2.3 协议还要规定通信过程

初学网络时,我们容易把协议理解成“约定一个结构体”。数据格式确实重要,但一套完整协议通常还要规定通信过程。

例如,客户端发出请求后,服务端是否必须应答;超过多长时间没有应答算超时;同一条消息是否允许重复;数据过大时怎样拆分;收到错误数据怎样处理。这些都属于协议的一部分。

所以协议可以从三个角度理解:

  • 语法:数据按照什么格式组织,每个字段多长;
  • 语义:每个字段代表什么,取不同值时应该怎样处理;
  • 时序:消息先后顺序怎样安排,什么时候发送,什么时候等待。
只统一字段格式,不统一字段含义和交互顺序,双方仍然无法正常通信。网络协议要让不同实现表现出一致的通信行为。

三、协议为什么要分层

3.1 一个协议解决不了所有问题

网络通信要处理的事情不少:数据怎样变成电信号,局域网内怎样找到网卡,跨网络怎样选择路径,数据丢失后怎样处理,最终又该交给哪个应用程序。

如果把这些逻辑全部塞进一个协议,协议会十分庞大,任何局部修改都可能影响整个系统。于是网络协议采用分层设计,每一层只关心自己负责的问题,并向上层提供相对稳定的服务。

协议分层和软件工程中的模块化思想一样:

  • 每一层有明确职责;
  • 上层使用下层提供的接口;
  • 下层实现发生变化时,尽量不影响上层;
  • 同一层的双方按照相同协议解释数据。

3.2 用打电话理解分层

下面这张图把通信分成“语言层”和“通信设备层”。

A 和 B 使用中文交流,属于语言层的约定;两部电话怎样编码、传输和还原声音,属于通信设备层的约定。

站在 A 的视角,他好像直接在和 B 说话。站在工程实现的视角,A 先把声音交给电话,电话把信号传给另一部电话,最后再由电话还原给 B。

这里先记住三点:

1. 逻辑上,同层之间在直接通信。 A 与 B 遵守相同的语言规则,两部电话也遵守相同的设备通信规则。
2. 实现上,数据要逐层交付。 A 不能绕过自己的电话,直接把声音交给 B 的电话内部电路。
3. 分层可以降低耦合。 A 和 B 把中文换成英语,不要求电话线路跟着修改;座机换成手机,也不要求人类重新设计语言。

同层之间按照协议进行逻辑通信,相邻层之间通过接口搞定真实的数据交付。

网络协议栈就是更繁琐的分层系统。我们既要保留“主机 A 正在和主机 B 通信”的整体视角,也要能沿着协议栈逐层分析数据经过了什么处理。

3.3 协议、服务和接口

分层以后,经常会遇到协议、服务和接口三个词,它们关注的方向不同。

  • 协议描述同一层通信双方应当遵守的规则;
  • 服务描述下层能为上层搞定什么事情;
  • 接口是上层使用下层服务的入口。
例如应用程序调用 Socket 接口,把数据交给操作系统。站在应用层看,操作系统提供了发送和接收服务;站在两台主机的传输层看,双方还要按照 TCP 或 UDP 的规则解释报文。

同层协议是横向关系,层与层之间的接口是纵向关系。图中经常画成“应用层直接和对端应用层通信”,那是逻辑关系;真实数据仍要通过本机下层接口向下传递。

3.4 分层带来的好处和代价

分层最直接的好处是解耦。只要接口保持稳定,某一层的实现可以替换。例如底层从有线网络换成无线网络,应用程序仍然可以使用同样的 Socket 接口;浏览器从 HTTP/1.1 升级到 HTTP/2,也不要求网卡驱动跟着变化。

分层还便于定位问题。网页打不开时,可以分别检查物理连接、链路状态、IP 配置、端口连通性和应用服务,而不是面对一个无法拆开的整体。

当然,分层并非没有代价。每层添加报头会增加数据开销,逐层处理也需要时间;某些功能可能在不同层重复出现。工程上仍然选择分层,是因为它带来的可维护性、兼容性和扩展性更重要。

四、OSI 七层模型

OSI 的全称是 Open Systems Interconnection,即开放系统互连。它把网络通信划分为七层,是一套逻辑参考模型。

从上到下分别是:

1. 应用层;
2. 表示层;
3. 会话层;
4. 传输层;
5. 网络层;
6. 数据链路层;
7. 物理层。

OSI 模型的优点是概念划分清楚,能帮助我们从职责上分析网络系统。不过,互联网的实际工程实现并没有完整照搬七层结构。会话层、表示层的不少工作通常由应用程序或具体库搞定,工程上更常使用 TCP/IP 四层或五层模型。

OSI 用来帮助我们理解分层,TCP/IP 更接近互联网的实际工程实现。 后续写网络程序时,重点会放在 TCP/IP 协议栈上。

OSI 七层模型负责建立认知框架,TCP/IP 四层或五层模型负责解释真实网络怎样工作。

七层模型中,表示层负责数据表示、编码和转换,会话层负责建立和管理会话。实际编程时,这些能力并没有消失,只是未必以独立内核层存在。例如 JSON 序列化、字符编码、TLS 加密、登录会话和连接状态,往往由应用程序或用户态库负责。

于是不能把“TCP/IP 没有单独的表示层、会话层”理解成这些工作不需要做。它们仍然存在,只是被合并到了应用层的实现中。

五、TCP/IP 五层模型

5.1 TCP/IP 不是一个协议

TCP/IP 经常被当作一个整体名称,但它实际表示的是一组协议,也就是一个协议族。IP、TCP、UDP、ICMP、ARP 等协议各有职责,共同完成网络通信。

学习时一般把 TCP/IP 分成五层:

1. 应用层;
2. 传输层;
3. 网络层;
4. 数据链路层;
5. 物理层。

如果把物理层和数据链路层合并为网络接口层,就获得常见的 TCP/IP 四层模型。两种说法并不冲突,只是划分粒度不同。

5.2 物理层

物理层负责传递最原始的比特信号。 双绞线、同轴电缆、光纤和无线电波都属于这一层讨论的范围。

它关心的是信号如何表示 0 和 1、传输距离有多远、速率是多少、抗干扰能力怎样。早期的集线器工作在物理层,它不会理解上层数据,只负责信号转发和放大。

网络编程主要处理软件问题,因此物理层通常不会成为代码学习的重点,但它是所有上层通信的基础。

5.3 数据链路层

数据链路层负责相邻设备之间的数据帧传送和识别。 网卡驱动、MAC 地址、帧同步、差错检测和局域网冲突处理,都属于这一层的东西。

常见的局域网技术包括以太网和无线 LAN。交换机主要工作在数据链路层,它依据 MAC 地址在局域网内部转发数据帧。

这一层解决的是“当前这一段链路,数据下一步交给谁”。它并不负责规划从北京到上海的完整路线,而是先保证数据能从当前设备到达下一台设备。

5.4 网络层

网络层负责地址管理和路由选择。 IP 协议通过 IP 地址标识主机所在的网络位置,路由器根据目的 IP 和路由表决定数据下一步应该转发到哪里。

如果数据链路层处理的是“一站”,网络层处理的就是“完整方向”。数据跨越多个局域网时,每经过一个路由器,下一跳可能变化,但目的 IP 仍然提供最终方向。

5.5 传输层

传输层位于主机内部,负责两台主机上进程之间的数据传输。 TCP 和 UDP 是这一层最典型的协议。

TCP 提供面向连接、可靠的字节流服务,会处理确认、重传、顺序和流量控制等问题。UDP 更轻量,不保证可靠交付,但开销较小、发送方式直接。

传输层还会使用端口号区分进程。数据到达一台主机以后,IP 地址只能说明“到哪台机器”,端口号才进一步说明“交给机器中的哪个进程”。端口号会在下篇详细展开。

5.6 应用层

应用层直接服务于用户程序。 HTTP、HTTPS、DNS、SSH、FTP 等都属于应用层协议。

浏览器访问网页、终端远程登录服务器、程序上传文件,最终都是应用层按照特定格式组织数据,再把数据交给下层协议栈处理。

我们的网络编程主要发生在应用层。程序员通常不需要自己实现网卡驱动、IP 路由和 TCP 重传,而是通过 Socket 接口使用操作系统已经提供好的协议栈。

5.7 不同设备工作在哪一层

从主要职责看:

  • 普通主机需要运行完整的 TCP/IP 协议栈;
  • 路由器重点实现网络层及以下功能;
  • 交换机重点实现数据链路层及以下功能;
  • 集线器只处理物理层信号。
这只是帮助理解的基本划分。现代设备常常会跨层工作,例如三层交换机具备部分路由能力,路由器也可能提供端口转发、防火墙和应用层管理功能。
设备工作层次不是死记表格。 判断设备属于哪一层,要看它转发数据时主要读取哪一层的地址和报头。

5.8 一次发送会经过哪些层

假设浏览器准备向服务器发送一条 HTTP 请求。浏览器先按 HTTP 规则组织应用数据,再通过 Socket 把数据交给内核。传输层增加 TCP 控制信息,网络层增加 IP 地址信息,链路层增加当前局域网需要的 MAC 信息,最后由物理层把数据表示为信号发送出去。

接收端按照相反顺序处理:网卡接收信号,链路层识别帧,网络层处理 IP 数据报,传输层把字节交给对应 Socket,服务器程序最后解析 HTTP 请求。

从浏览器视角看,它只是在调用接口发送 HTTP 数据;从协议栈视角看,一条应用消息已经被多层协议共同处理。后面见到“应用层直接和应用层通信”时,应该理解为逻辑上的同层通信,而不是数据跨过了中间层。

六、为什么需要 TCP/IP 协议栈

6.1 距离变长以后,问题变多了

计算机内部本身也存在通信。CPU、内存、磁盘和其他设备通过总线交换数据,它们同样有自己的接口和协议。

网络通信仍然是设备之间传递数据,只是通信双方从一台主机内部,变成了相隔很远的两台主机。距离变长以后,会出现本地通信中不明显的新问题:

1. 数据丢失怎么办? 传输介质和中间设备都可能出错;
2. 怎样找到目标主机? 世界上有大量网络和主机,不能靠一根直连线路定位;
3. 当前应该转发到哪里? 数据通常要经过多个中间节点;
4. 到达主机后交给谁? 一台主机同时运行很多进程,收到数据不是通信的终点。

这些问题具有天然层次:链路层处理相邻设备,网络层负责地址和路由,传输层处理端到端传输,应用层解释和使用数据。问题可以分层,解决问题的协议也就可以分层。

TCP/IP 协议栈就是一套长距离网络通信方案。学习网络的过程,就是逐层研究这些问题为什么出现,以及每层协议怎样处理。

TCP/IP 协议栈把长距离通信产生的问题拆开,再交给不同层处理。

这里还要要注意,“传输层负责两台主机之间的数据传输”是一种简化说法。真正使用网络数据的是进程,传输层建立的是进程到进程的端到端通信。 IP 地址先把数据送到目标主机,端口号再把数据交给目标进程。这个细节会在下篇展开。

6.2 TCP/IP 与操作系统的关系

网络协议不是只存在于书本中的规则,它最终要由软件实现。对 Linux 来说,传输层、网络层和数据链路层的大量逻辑都在内核中,网卡还需要驱动程序配合。

用户程序准备好数据后,通过 Socket 接口进入内核。内核按照协议栈逐层封装,最后由网卡把数据发出去。接收时顺序相反:网卡先收到数据,内核逐层解析,最后把有效数据交给对应进程。

这意味着网络通信不能绕开操作系统。应用程序只负责自己这一层的业务格式,剩下的传输、路由和链路处理由内核协议栈完成。

6.3 为什么协议栈适合放在内核

协议栈需要直接管理网卡、接收中断、维护连接状态,还要在多个进程之间安全地分配网络资源。这些工作天然适合由操作系统统一完成。

如果每个应用都自己驱动网卡、处理路由和重传,代码会大量重复,程序之间也容易互相干扰。操作系统把底层能力集中起来,再通过系统调用向用户态提供统一接口,应用程序只需要关心自己的业务协议。

这和文件系统的设计很相似。程序不必知道磁盘扇区怎样读写,只需要调用 open、read、write;网络程序也不必直接操作网卡寄存器,只需要通过 Socket 使用内核协议栈。

七、协议在代码中是什么样的

“协议是一种约定”没有问题,但只停留在这句话上仍然比较抽象。站在代码角度,协议通常表现为一组明确的字段,以及解析这些字段的规则。

例如一个简单报文可以约定:前 4 个字节表示数据长度,后 2 个字节表示消息类型,剩余部分是正文。发送方按照这个格式构造数据,接收方按照相同格式解析。

协议的关键不在于是否真的使用 C 语言结构体,而在于双方必须对字段位置、长度、含义和处理顺序形成一致认识。

7.1 报头和有效载荷

协议一般会把数据分成两部分:

  • 报头:记录协议自身需要的控制信息;
  • 有效载荷:当前层真正要传递的数据。
对当前协议层来说,完整报文 = 当前层报头 + 当前层有效载荷。

一层协议收到上层数据后,会在前面添加自己的报头。对当前层来说,上层交下来的整块数据都是有效载荷。报文继续向下交付时,下一层还会再添加新的报头。

接收方则按照相反顺序处理。每一层读取并移除自己的报头,再把有效载荷交给上层。

要让这个过程成立,每层协议都必须解决两个问题:

1. 怎样把自己的报头与有效载荷分开;
2. 怎样判断有效载荷应该交给上层的哪个协议。

第一个问题对应解包,第二个问题对应分用。后面学习具体协议时,也可以沿着这两个问题去分析报文格式。

7.2 同一份数据在不同层有不同身份

同一串字节在不同层看来,身份并不相同。应用层把它看成请求正文,传输层把整个应用消息当成自己的有效载荷,网络层又把传输层报文当成有效载荷。

“报头”和“有效载荷”要相对于当前协议层来看。 进入下一层后,上一层的报头会和数据一起成为新的有效载荷。

这也解释了为什么抓包工具可以逐层展开报文:最外层先见到链路层字段,去掉链路层封装后是 IP 报文,再向内是 TCP 或 UDP,最里面才是应用数据。

八、两种观察网络通信的视角

网络初学阶段容易在“逻辑通信”和“真实路径”之间混淆。

站在用户视角,浏览器像是在直接访问服务器;站在应用层视角,客户端程序像是在直接和服务端程序交互。这样的理解没有错,因为通信双方遵守同层协议。

但站在实现视角,应用层数据必须交给传输层、网络层和数据链路层,再经过网卡与中间设备发送。对端收到后,还要自底向上逐层解析。

所以我们需要同时保留两种视角:

  • 横向看:同层协议双方在逻辑上直接通信;
  • 纵向看:真实数据在本机协议栈中逐层向下,在对端协议栈中逐层向上。
后面分析数据封装、路由转发和 Socket 收发时,这两种视角会反复出现。

九、这一阶段容易混淆的几个问题

9.1 网络分层不等于硬件被切成几块

分层首先是一种逻辑设计。某一层可以由内核代码实现,也可以由驱动、硬件或用户态库实现。不要看到五层模型,就认为计算机内部一定存在五块一一对应的硬件。

9.2 TCP/IP 四层和五层并不矛盾

五层模型把物理层和数据链路层分开,便于教学时观察底层职责;四层模型把它们合并为网络接口层,更接近 TCP/IP 协议族的传统划分。讨论时先确认采用哪种模型即可。

9.3 逻辑直连不代表物理直连

应用层双方按照相同协议通信,不代表数据真的从一个应用进程直接跳到另一个应用进程。中间仍要经过本机协议栈、传输介质、网络设备和对端协议栈。

9.4 协议标准不等于唯一代码实现

同一协议可以有多种实现。只要报文格式和对外行为符合标准,Linux、Windows、网络设备和嵌入式系统就能互操作。协议保证的是兼容,不是要求大家使用同一份源代码。

总结

这篇文章先建立了网络学习的整体框架:

1. 网络产生的原因:人需要协作,因此计算机之间也需要交换数据,网络从局域互联逐步发展为广域互联;
2. 连接与协议的区别:连接只提供传输通道,通信双方还必须遵守相同协议;
3. 协议分层的原因:网络问题繁琐且具有层次,所以协议栈采用分层设计;
4. 两种分层模型:OSI 七层模型适合建立概念,实际工程中主要使用 TCP/IP 四层或五层模型;
5. TCP/IP 的本质:它不是单个协议,而是一组解决长距离通信问题的协议;
6. 协议栈的实现位置:Linux 内核实现了主要协议栈,用户程序通过 Socket 接口使用它;
7. 数据的处理方式:协议在数据上体现为报头和有效载荷,发送时逐层封装,接收时逐层解包和分用。

下一篇继续沿着数据真正走过的路径,分析局域网通信、MAC 地址、IP 地址、跨网络转发,并补上端口号、字节序和 Socket 编程前必须理解的基础东西。

往期博客:
【Linux】线程安全进阶:单例模式、可重入函数与死锁排查
【Linux】手写日志与固定线程池:任务队列、工作线程和安全退出
【Linux】条件变量为什么必须配合互斥锁:从 pthread_cond_wait 到阻塞队列


这篇笔记就先到这里,后面用到新的思路或者发现有问题再补充。

评论 (0)

暂无评论