计算机网络发展背景
计算机研发出来就是为了计算的,既然如此数据传输是必不可少的。随着发展,就要面临不同计算机之间数据传输的问题,网络也会随之发展。
起初各个计算机都是独立的:

随后就发展出了网络互联,将多台计算机连接在一起完成数据共享:

再后来,计算机的数量更多了,通过交换机和路由器连接在一起(局域网LAN):

再后来就发展成能将远隔千里的计算机连接在一起(广域网WAN):

初识协议
所谓协议就是一种约定,约定好各自传输数据的格式和含义。
比如像摩斯密码,按一定的频率传递信息。当然只有这些是不够的,我们还需要完善协议的细节。
制定协议的组织
能定制协议标准的主体涵盖国际/区域性标准化组织、行业联盟,以及在技术领域有强影响力的科技巨头,它们或是制定通用标准,或是主导特定领域协议研发,具体如下:
- 国际通用标准化组织
- IEEE(电气和电子工程师协会):全球规模极大的专业技术团体,制定了诸多电子、通信领域核心协议标准。比如IEEE 802系列标准,像Wi-Fi对应的802.11标准、以太网对应的802.3标准,深刻影响局域网等网络技术的发展。
- IETF(互联网工程任务组):志愿性质的国际团体,是互联网核心协议的核心制定者。TCP、IP、HTTP等构成TCP/IP协议族的关键协议,均由其通过RFC文档确定和更新标准,主导着互联网基础通信规则的演进。
- ITU(国际电信联盟):联合国下属专门机构,其ITU - T部门专注电信标准化。像5G网络相关通信协议、传统电话通信协议等诸多电信领域标准都由其制定,保障全球电信网络的兼容性和互操作性。
- 区域及行业专项联盟
- ETSI(欧洲电信标准学会):推动欧洲电信领域标准制定,在4G、5G等移动通信标准方面贡献突出,制定的标准既适配欧洲市场需求,也注重与全球其他主流标准兼容,助力欧洲电信技术融入全球体系。
- 中国通信标准化协会(CCSA):国内通信行业核心标准化组织,制定了TD - LTE等契合国内通信发展需求的标准,同时积极推动国内标准与国际接轨,为国内通信企业参与国际竞争提供支撑。
- 蓝牙技术联盟(SIG):专注蓝牙协议标准的制定与推广,成员包含苹果、英特尔等科技企业。低功耗蓝牙(BLE)等主流蓝牙相关协议均由该联盟规划,推动蓝牙技术在各类智能设备中的普及。
- 科技巨头企业
- 华为、高通:在通信领域极具话语权,深度参与5G NR等关键通信协议的国际标准制定。凭借自身在通信技术上的深厚积累和大量专利,能够影响协议的技术方向和核心参数设定。
- 谷歌、亚马逊:主导多款应用层协议标准。例如谷歌参与推动的HTTP/3协议,大幅提升了网页传输效率;亚马逊则推出Amazon Sidewalk等智能家居相关协议,影响智能家居设备间的通信规则。
- 泰凌微电子:聚焦物联网领域,自研低功耗蓝牙、Zigbee、Thread及Matter等协议栈,不仅掌握这些协议的核心技术,还能根据智能遥控、智能家居等特定场景需求,提供定制化的协议解决方案。
- 跨界标准定制企业
- DocuSign:虽非传统网络协议领域企业,但开创了电子签名领域的全球标准。其推出的智能协议管理平台,还能为企业定制合同、保密协议等各类业务协议的管理流程与标准,适配不同行业的业务协议需求。
- 招商轮船:联合多家权威单位编制并发布了船用燃料领域的两项团体标准,这是中国首次在该领域推出的权威性团体标准,为船用燃料行业制定了新的行业协议规范。
协议分层
协议本质也是软件,在设计上为了更好的进行模块化,解耦合,也是被设计成为层状结构的。
OSI七层模型
• OSI(OpenSystemInterconnection,开放系统互连 )七层网络模型称为开放式系统互联参考模型,是一个逻辑上的定义和规范;
• 把网络从逻辑上分为了7层.每一层都有相关、相对应的物理设备,比如路由器,交换机;
• OSI七层模型是一种框架性的设计方法,其最主要的功能使就是帮助不同类型的主机实现数据传输;
• 它的最大优点是将服务、接口和协议这三个概念明确地区分开来,概念清楚,理论也比较完整.通过七个层次化的结构模型使不同的系统不同的网络之间实现可靠的通讯;
• 但是,它既复杂又不实用;所以我们按照TCP/IP四层模型来讲解.
| 分层名称 | 功 能 | 每层功能概览 |
|---|---|---|
| 7 应用层 | 针对特定应用的协议。 | 针对每个应用的协议 电子邮件 ➡️ 电子邮件协议 远程登录 ➡️ 远程登录协议 文件传输 ➡️ 文件传输协议 |
| 6 表示层 | 设备固有数据格式和网络标准数据格式的转换。 | 接收不同表现形式的信息,如文字流、图像、声音等 |
| 5 会话层 | 通信管理。负责建立和断开通信连接(数据流动的逻辑通路)。管理传输层以下的分层。 | 何时建立连接,何时断开连接以及保持多久的连接? |
| 4 传输层 | 管理两个节点之间的数据传输。负责可靠传输(确保数据被可靠地传送到目标地址)。 | 是否有数据丢失? |
| 3 网络层 | 地址管理与路由选择。 | 经过哪个路由传递到目标地址? |
| 2 数据链路层 | 互连设备之间传送和识别数据帧。 | 数据帧与比特流之间的转换 |
| 1 物理层 | 以"0"、"1"代表电压的高低、灯光的闪灭。界定连接器和网线的规格。 | 比特流与电子信号之间的切换 |
- 其实在网络角度,OSI定的协议7层模型其实非常完善,但是在实际操作的过程中,会话层、表示层是不可能接入到操作系统中的,所以在工程实践中,最终落地的是5层协议。
TCP/IP五层(或四层)模型
TCP/IP是一组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇
TCP/IP通讯协议采用了5层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求.
- 物理层:负责光/电信号的传递方式.比如现在以太网通用的网线(双绞线)、早期以太网采用的的同轴电缆(现在主要用于有线电视)、光纤,现在的wifi无线网使用电磁波等都属于物理层的概念。物理层的能力决定了最大传输速率、传输距离、抗干扰性等.集线器(Hub)工作在物理层.
- 数据链路层:负责设备之间的数据帧的传送和识别.例如网卡设备的驱动、帧同步(就是说从网线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就自动重发)、数据差错校验等工作.有以太网、令牌环网,无线LAN等标准.交换机(Switch)工作在数据链路层.
- 网络层:负责地址管理和路由选择.例如在IP协议中,通过IP地址来标识一台主机,并通过路由表的方式规划出两台主机之间的数据传输的线路(路由).路由器(Router)工作在网路层.
- 传输层:负责两台主机之间的数据传输.如传输控制协议(TCP),能够确保数据可靠的从源主机发送到目标主机.
- 应用层:负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等.我们的网络编程主要就是针对应用层.
物理层我们考虑的比较少,我们只考虑软件相关的内容.因此很多时候我们直接称为TCP/IP四层模型.
再识协议
所以为什么要有TCP/IP协议,你们真的明白了吗?
我们本地通信的时候就不见得有这么复杂的协议,远程就需要了。因为出问题的解决成本变高了。就好像你的女朋友如果和你同一个城市,她生气了就能直接去哄她,但如果是异地恋其中变数就多了。
所以,为什么要有TCP/IP协议?本质就是通信主机距离变远了
那么什么是TCP/IP协议
- TCP/IP协议的本质是一种解决方案
- TCP/IP协议能分层,前提是因为问题们本身能分层
我们来看一个重点TCP/IP 协议与操作系统的关系:

如上我的传输层和网络层都是在OS内核实现的,因此在网络通信里占据主导地位,又因为传输层和网络层的代表协议是TCP和IP,故称为TCP/IP模型。
有了传输层和网络层的协议,无论我们的操作系统是什么,他们对应的实现都是一致的。这样我们才能在不同操作系统之间通信:

迄今为止,我们已经能尝试用朴素的概念来理解协议了。
首先OS源代码一般都是用C/C++语言写的,我们看下图:

假设我们在任意一层定义一个结构体。
现在我们将这个结构体对象从主机A发送给主机B,到了对应层,主机B能否直接识别主机A发来的信息?答案是肯定的,既然规定了结构体,我们就可以依据结构体来解析数据!
所以我们这里输出一个重要结论:
所谓协议,就是通信双方都认识的结构化的数据类型
那么我们这个结构化数据类型需要有什么信息?我们以送快递为例,这里是一个快递单的报头:

上面要记录各种信息,包括src和dest等等,然后快递报头加上快递本身就组成了一个可以传递的资源。
因此我们称这个结构化数据类型为报文,报文=报头+有效载荷
网络传输基本流程
局域网网络传输流程图
我们现以以太网为例,阐述以太网内不同主机是如何通信的。
以太网(Ethernet)是一种广泛使用的局域网(LAN)技术,用于设备间的有线数据传输。它由IEEE 802.3标准定义,支持从10 Mbps到400 Gbps的多种速率,适用于家庭、企业及数据中心网络。
首先每台主机(局域网)要通信就要由一个唯一标识:MAC地址
MAC地址(Media Access Control Address)是网络设备的物理地址,用于在局域网(LAN)中唯一标识设备。它由48位二进制数组成,通常表示为12个十六进制字符(如00:1A:2B:3C:4D:5E),由设备制造商分配并固化在网卡中。
Windows里能通过ipconfig指令查看自己的MAC地址。
Linux中可以通过ifconfig查看自己的MAC地址:

然后主机就可以根据MAC地址找到要目标主机,向对方发送信息。

在这里其他主机也可以接收到这个信息,只不过MAC地址不是dest所以选择忽略。
注意我们的数据传递本质要依靠硬件,因此同一时刻只允许一台主机向网络发送数据。
- 如果有多台同时发送,会发生数据干扰,我们称之为数据碰撞
- 所有发送数据的主机要进行碰撞检测和碰撞避免
- 没有交换机的情况下,一个以太网就是一个碰撞域
- 局域网通信的过程中,主机对收到的报文确认是否是发给自己的,是通过目标mac地址判定
以太网处理数据碰撞的方式主要是休眠一段时间后再发送。
除了以太网还有一种局域网叫令牌环
令牌环(Token Ring)是一种局域网(LAN)技术,由IBM在20世纪80年代提出。它通过一个特殊的帧(称为"令牌")在环形拓扑结构的网络中传递控制权,确保同一时间只有一个设备可以发送数据,从而避免冲突。
相当于我们前面学习的上锁,每个令牌环要持有锁才能发送信息。
初步明白了局域网通信原理,再来看同一个网段内的两台主机进行发送消息的过程:

但是注意我们每一层都有协议,因此我们每一层传输信息都要增加报头向下传输,这个过程称为封装。获取信息后则要对信息进行解包,此外我们还要根据其协议分配给不同的上层协议,该过程称为分用:

有没有发现我们封装过程中增加报头相当于一个压栈过程,解包的时候去掉报头就是一个弹栈的过程。
因此TCP/IP叫做网络协议栈
通过这个图我们知道了网络协议的两条共性:
- 报头和有效载荷的分离
- 除了应用程,每一程协议,都必须解决一个问题,自己的有效载荷,应该交给上一层的哪个协议,即分用
注意我们每一层的有效载荷部分都是不同的。

我们再明确一下完整报文的叫法:
不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做
数据报(datagram),在链路层叫做帧(frame).
跨网络传输流程图
首先我们跨网络通信又要有一个唯一标识,这个标识称为IP地址
IP 协议有两个版本,IPv4和IPv6. 我们整个的课程,凡是提到IP协议,没有特殊说明的,默认都是指IPv4
- IP地址是在IP协议中,用来标识网络中不同主机的地址;
- 对于IPv4来说,IP地址是一个4字节,32位的整数;
- 我们通常也使用"点分十进制"的字符串表示IP地址,例如192.168.0.1;用点分割的每一个数字表示一个字节,范围是0-255;
IPv6(Internet Protocol version 6)是下一代互联网协议,用于解决IPv4地址耗尽问题。IPv6采用128位地址长度,提供约3.4×10³⁸个唯一地址,显著扩展了地址空间。同时,IPv6优化了路由效率、安全性(内置IPSec)和自动配置功能(如无状态地址自动配置SLAAC)
那么我们来看看跨网络数据传输:

首先我们数据层都应该实现一个路由的功能。当向下传递信息发现不是局域网的IP地址时,就会将数据交给路由器。
路由器要连通不同的局域网就必须有不同的网卡。
注意不同网卡的MAC地址和IP地址都不同。
然后通过路由器将数据传给另一个局域网。
也就是传递信息的时候MAC地址会随之改变,在数据链路层的报文内容就不一样。
- 但是网络层以上(包括网络层)的报文内容完全一致!因此IP可以屏蔽底层网络的差异。所有网络都是IP网络。
IP地址VSMAC地址
- IP地址在整个路由过程中,一直不变(目前,我们只能这样说明,后面在修正)
- Mac地址一直在变
- 目的IP是一种长远目标,Mac是下一阶段目标,目的IP是路径选择的重要依据,mac地址是局域网转发的重要依据
IP网络的意义和网络通信的宏观流程

Socket编程
首先我们数据传输了,必然是要读数据。那么传输数据和读数据的载体是什么?学完Linux系统编程的我们知道,载体自然就是进程!
所以说网络的本质就是进程间通信。
那么我们自然需要一个进程的唯一标识。这就需要端口号(port)了:
端口号(port)是传输层协议的内容.
- 端口号是一个2字节16位的整数;
- 端口号用来标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理;
- IP地址+端口号(Socket)能够标识网络上的某一台主机的某一个进程;
- 一个端口号只能被一个进程占用.
端口号的范围划分:
- 0-1023:知名端口号,HTTP,FTP,SSH等这些广为使用的应用层协议,他们的端口号都是固定的
- 1024-65535:操作系统动态分配的端口号.客户端程序的端口号,就是由操作系统从这个范围分配的.
其实我们之前学过的PID也能唯一标识进程,为什么还需要一个端口号呢?
当然是为了解耦了,我们要将网络和OS分开,其中一个出了BUG也不会影响另一个。
综上,IP地址用来标识互联网中唯一的一台主机,port用来标识该主机上唯一的网络进程。
一个网络进程IP+Port就能表示互联网中唯一的一个进程
我们把ip+port叫做套接字socket
传输层的典型代表
传输层代表协议有TCP和UDP
TCP(Transmission Control Protocol 传输控制协议)
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
UDP(UserDatagramProtocol 用户数据报协议)
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
从这两种协议的特征我们就能看得出,UDP实现较为简单,我们的学习自然是由浅入深。
网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分。
小端字节序就是权值小的字节存放在低地址,简称小小小,大端字节序反之。
我们可以编写一个简单的程序来查看当前文件是大端字节序还是小端字节序:

输出结果:
小端
看来我的主机是小端字节序呢。
磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?
别想着从报头里定义是大端还是小端,那我问你,你不知道大小端怎么找到报头>.<
因此我们要在协议上直接规定,统一使用大端字节序!
- 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
- 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
- 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
- TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
- 不管这台主机是大端机还是小端机,都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
- 如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略,直接发送即可;
socket 编程接口
c
C
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,
socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,
socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
sockaddr 结构
socket API 是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及UNIX Domain Socket.然而,各种网络协议的地址格式并不相同.
- IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型,16位端口号和32位IP地址.
- IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6.这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.
- socketAPI可以都用structsockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性,可以接收IPv4, IPv6, 以UNIXDomainSocket 各种类型的sockaddr结构体指针做为参数;
这种实现方式我们在进程间通信也提到过,就是C语言实现的多态。
这样我们其实就能通过socket实现网络通信和本地通信。