一、前言
Linux 网络编程是基于 Linux 操作系统的网络通信开发技术,核心围绕Socket 接口展开,涵盖 TCP/UDP 协议应用、IO 模型优化、高并发处理等核心内容,广泛应用于服务器开发、嵌入式通信、分布式系统等场景。
二、网络的体系结构
2.1、OSI七层模型
OSI七层模型是国际标准化组织(ISO)于 1984 年制定的网络通信理论框架,核心思想是通过 "分层解耦" 将复杂的网络通信过程拆解为 7 个独立的功能模块,每层通过标准化接口为上层提供服务、向下层请求服务,最终实现 "异种计算机系统的互联互通"。如下图所示:

**应用层:**就是应用软件使用的协议,如邮箱使用的POP3,SMTP、远程登录使用的Telnet、获取IP地址的DHCP、域名解析的DNS、网页浏览的http协议等;这部分协议主要是规定应用软件如何去进行通信的。
**表示层:**决定数据的展现(编码)形式,如同一部电影可以采样、量化、编码为RMVB、AVI,一张图片能够是JPEG、BMP、PNG等。
**会话层:**为两端通信实体建立连接(会话),中间有认证鉴权以及检查点记录(供会话意外中断的时候可以继续,类似断点续传)。
**传输层:**将一个数据/文件斩件分成很多小段,标记顺序以被对端接收后可以按顺序重组数据,另外标记该应用程序使用的端口号及提供QOS。(不同的应用程序使用不同计算机的端口号,同样的应用程序需要使用一样的端口号才能正常通信)
**网络层:**路由选路,选择本次通信使用的协议(http、ftp等),指定路由策略及访问控制策略。(IP地址在这一层)
**数据链路层:**根据端口与MAC地址,做分组(VLAN)隔离、端口安全、访问控制。(MAC地址在这一层)处理VLAN内的数据帧转发,跨VLAN间的访问,需要上升到网络层。
**物理层:**将数据最终编码为用0、1标识的比特流,然后传输。(例如将题主头像的图片,变为一串01100111100这样的数字来表示)。
OSI七层模型相关的协议已经很少使用,但模型本身非常通用,这里了解即可。
2.2、TCP/IP 四层模型
TCP/IP 四层模型是实际应用的核心,需逐一掌握每层的核心功能、典型协议、关键设备、数据单元、编程关注点,这直接关联后续网络编程、数据传输问题排查(如 CFD 多节点通信故障)。与OSI七层模型有所不同,如下图所示:

1、应用层:主要有负责web浏览器的HTTP协议, 文件传输的FTP协议,负责电子邮件的SMTP协议,负责域名系统的DNS等。
2、传输层:主要是有可靠传输 的TCP协议,特别高效 的UDP协议。主要负责传输应用层的数据包。
3、网络层:主要是IP协议。主要负责寻址(找到目标设备的位置)。
4、链路层:主要是负责转换数字信号和物理二进制信号。
用一个通俗点的例子讲,比如你要写要寄一个快递给你的朋友张三,你在快递单上写的内容对应的是应用层,传输层对应的是快递是否保价、是否签收、是否补发,网络层对应的是快递怎么跨城市、走哪条路线,链路层对应的是用什么交通工具来运快递,如下图所示:
| TCP/IP 层 | 快递系统里的角色 |
|---|---|
| 应用层 | 你写在快递单上的"内容和说明" |
| 传输层 | 快递是否保价、是否签收、是否补发 |
| 网络层 | 快递怎么跨城市、走哪条路线 |
| 网络接口层 | 卡车 / 飞机 / 传送带 |
TCP/IP 四层模型就像现代快递体系:应用层写清楚"送什么",传输层保证"送得准不准",网络层决定"怎么走",网络接口层负责"怎么运",各层分工明确,协同完成一次可靠通信。
2.3、TCP/IP协议族
从字面意义上来讲,TCP/IP是指传输层 的TCP协议和网络层 的IP协议。实际上,TCP/IP只是利用 IP 进行通信时所必须用到的协议群的统称。即他们都是基于IP协议,于是拿出最常用的TCP协议和IP协议组团,代表整个协议族出道。
具体来说,在网络层是IP/ICMP协议、在传输层是TCP/UDP协议、在应用层是SMTP、FTP、以及 HTTP 等。他们都属于 TCP/IP 协议。如下图所示: 
他们与 TCP 或 IP 的关系紧密,是实现互联网必不可少的组成部分。
所以TCP/IP 一词其实是泛指这些协议,TCP/IP 也被称为网际协议群。互联网进行通信时,需要相应的网络协议,TCP/IP 原本就是为使用互联网而开发制定的协议族。因此,互联网的协议就是 TCP/IP,TCP/IP 就是互联网的协议。

2.4、网络的封包和拆包
通过四层模型可以将应用层的具体数据传输给对应设备,比如,我们需要发送一个index.html 。两台电脑在应用层都使用HTTP协议(即都使用浏览器)。在传输层,TCP协议会将HTTP协议发送的数据看作一个数据包,并在这个数据包前面加上TCP包的一部分信息(部首)在网络层,IP协议会将TCP协议要发送的数据看作一个数据包,同样的在这个数据包前端加上IP协议的部首在数据链路层,对应的协议也会在IP数据包前端加上以太网的部首。

源设备和目标设备通过网线连接,就可以通过物理层的二进制传输数据。数据链路层,会使用对应的协议找到物理层的二进制数据,解码得到以太网的部首信息和对应的IP数据包,再将IP数据包传给上层的网络层。数据链路层>网络层>传输层>应用层,一层层的解码,最后就可以在浏览器中得到目标设备传送过来的index.html。

三、网络编程基础知识
3.1、Socket
Socket(套接字)是 操作系统内核提供的网络通信抽象接口,是连接应用层与传输层的桥梁,也是 Linux 网络编程的核心基础。其本质是一个 "文件描述符"(与文件、管道、设备等统一的 IO 模型),支持 "打开 - 读写 - 关闭" 的标准 IO 操作,屏蔽了底层 TCP/IP 协议栈的复杂细节,让应用程序能便捷地实现跨设备、跨网络的通信。
3.1.1、定义
1、Socket 是 "通信端点":两个应用程序通过网络通信时,各自通过一个 Socket 标识自己(类似 "电话号码 + 分机号"),通信本质是 "两个 Socket 之间的数据交互"。
2、Socket 是 "协议无关接口":同一套 Socket 接口可适配 TCP、UDP、原始协议等不同传输层协议,仅需在创建时指定协议类型。
3、Socket 遵循 "Everything is a file":Linux 系统将所有 IO 资源抽象为文件描述符(整数),Socket 也不例外。因此 read()、write()、close()等文件操作函数可直接用于 Socket 通信,降低了编程复杂度。
4、Socket 位于 应用层与传输层之间,向上为应用程序提供标准化的通信接口,向下封装传输层协议(TCP/UDP)的实现细节(如三次握手、重传机制),让开发者无需关注底层协议栈的具体实现,仅需调用接口即可完成通信。
3.1.2、分类
Socket 按 "通信类型" 可分为三类,核心差异体现在传输层协议、可靠性、数据格式等方面,需根据应用场景选择:
1、流式套接字(SOCK_STREAM):唯一对应TCP,提供了一个面向连接,可靠的数据传输服务,数据无差错,无重复的发送顺序接收。内射击流量控制,避免数据流淹没慢的接收方。数据被看作式字节流,无长度限制。
2、数据包套接字(SOCK_DGRAM):唯一对应UDP,提供无连接服务器,数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
3、原始套接字(SOCK_RAW):对应多个协议,发送穿透了传输层,可以对较低层次协议如IP,ICMP直接访问。
3.2、IP地址
IP 地址(Internet Protocol Address)是TCP/IP 协议栈网络层的核心地址标识,用于唯一标识互联网中设备(如 PC、服务器、传感器、路由器)的 "网络位置",是跨网络数据传输的 "逻辑地址"------ 如同现实中的 "街道地址",确保数据能从源设备准确路由到目标设备。
3.2.1、定义
IP 地址是32 位(IPv4)或 128 位(IPv6)的二进制数,为了便于人类阅读,通常转换为十进制(IPv4)或十六进制(IPv6)格式。每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由。
表示的形式:常用点分形式,如202.38.64.10,最后都会转化成一个32位的无符号整数。
3.2.2、核心作用
1、设备标识:唯一标识网络中的终端设备或网络设备(如路由器接口)。
2、路由寻址:通过 IP 地址确定数据传输的路径(如从实验室 PC 到云端服务器,路由器通过 IP 地址选择路由)。
3、分层协作:IP 地址工作在网络层,与链路层的 MAC 地址(物理地址)配合 ------IP 负责 "跨网络寻址",MAC 负责 "同一局域网内传输"(通过 ARP 协议实现 IP 与 MAC 的映射)。
3.2.3、与 MAC 地址的核心区别
区别如下: 
3.3、端口号
端口号(Port Number)是 TCP/IP 协议栈传输层 的核心标识,用于唯一区分同一设备上的不同网络应用程序(进程)。它与网络层的 IP 地址配合,构成 "IP 地址 + 端口号" 的完整通信端点(Socket 地址),确保数据能从源设备的某个进程准确传输到目标设备的对应进程 ------ 如同现实中 "街道地址 + 门牌号",IP 地址定位 "大楼",端口号定位 "房间"。
3.3.1、定义
端口号是 16 位无符号整数(取值范围:0~65535),由操作系统分配和管理,用于标识设备上的网络进程。
3.3.2、核心作用
1、 进程标识:同一设备上可能同时运行多个网络应用(如浏览器、FTP 客户端、仿真软件),端口号用于区分这些应用,确保数据不会发送到错误进程。
2、端到端通信:传输层协议(TCP/UDP)通过端口号实现 "进程到进程" 的通信,而非仅 "设备到设备"(IP 地址的作用)。
3、协议绑定:特定应用层协议通常默认使用固定端口号(如 HTTP 默认 80 端口),简化通信配置(无需手动指定端口)。
3.3.3、与 IP 地址的协同关系
1、完整通信端点:IP 地址+端口号(如192.168.1.100:8080),称为 "套接字地址"(Socket Address),是网络通信的唯一标识。
2、协同逻辑:IP 地址:负责跨网络路由,将数据从源设备送达目标设备(如从实验室 PC 到云端服务器)。端口号:负责设备内分发,将数据从目标设备的网络栈送达具体应用进程(如从服务器的网卡到仿真数据接收程序)。
示例:实验室 PC(IP:192.168.1.5,端口:54321)通过 TCP 连接访问云端服务器(IP:203.0.113.8,端口:8080),数据先通过 IP 路由到服务器,再通过端口 8080 交付给服务器上的仿真数据接收进程。
3.4、字节序
字节序是多字节数据在计算机内存中的存储顺序,核心解决 "如何将 16 位、32 位等多字节数据拆分为单个字节(8 位)存储" 的问题。由于不同 CPU 架构(如 x86、PowerPC、ARM)的字节序存在差异,跨设备 / 跨平台通信(如网络编程、多节点仿真数据传输)必须统一字节序标准,否则会导致数据解析错误(如端口号、IP 地址、仿真数值读取异常)。
3.4.1、本质
计算机最小存储单位是 "字节(Byte,8 位)",但实际应用中需处理多字节数据(如 16 位端口号、32 位 IP 地址、32 位浮点数、64 位整数)。例如,数值0x12345678(32 位十六进制,对应十进制 305419896)由 4 个字节组成:0x12(高位字节)、0x34、0x56、0x78(低位字节)。字节序定义了这 4 个字节在内存中的排列顺序。
高位字节:多字节数据中权重较高的字节(如0x12345678中的0x12,对应 2^24~2^31 位)。
低位字节:多字节数据中权重较低的字节(如0x12345678中的0x78,对应 0~7 位)。
内存地址:计算机内存以字节为单位编址,每个字节对应唯一的内存地址(如0x00000000、0x00000001),地址从小到大递增。
3.4.2、字节序的分类与原理
字节序分为两类,核心差异在于 "高位字节与低位字节的存储地址顺序":
1、小端序
定义:低位字节存低地址,高位字节存高地址("小的在前")。低对低,高对高。
存储示例:以 32 位数据0x12345678为例(内存地址从0x00开始):

特点:符合人类 "从低位到高位" 的计算习惯(如加法先算低位);主流 CPU 架构默认采用(x86、x86_64、ARMv7+(默认小端))。跨设备通信时需转换字节序(否则数据错乱)。
2、大端序
定义:高位字节存低地址,低位字节存高地址("大的在前")。高对低,低对高。
存储示例:同样 32 位数据0x12345678(内存地址从0x00开始):

特点:字节顺序与数据的 "书写顺序" 一致,直观易读。网络通信的标准字节序 (TCP/IP 协议栈规定),所有网络传输的数据必须采用大端序。部分 CPU 架构支持(PowerPC、SPARC、ARMv7+(可配置为大端))。
3.4.3、网络编程中的字节序转换
1、为什么必须转换字节序
网络通信的本质是 "跨设备数据传输 ",不同设备可能采用不同字节序(如 x86 服务器(小端)与 ARM 传感器(小端)、PowerPC 服务器(大端)通信)。TCP/IP 协议栈规定:所有网络传输的数据(端口号、IP 地址、应用层数据)必须采用大端序(称为 "网络字节序")。
结论:发送方:将 "主机字节序"(本地 CPU 的字节序)转换为 "网络字节序"(大端序)。
接收方:将 "网络字节序" 转换为 "主机字节序",再解析数据。
2、核心转换函数
Linux 系统提供 4 个标准函数(头文件<netinet/in.h>),专门用于字节序转换,无需手动处理位运算:
|---------|-----------------------------------|-----------|-----------------------------------------------|
| 函数名 | 功能 | 输入 / 输出类型 | 适用场景 |
| htons() | Host to Network Short(主机→网络,16 位) | 16 位整数 | 端口号转换(如 8080→网络字节序) |
| htonl() | Host to Network Long(主机→网络,32 位) | 32 位整数 | IPv4 地址转换(如 INADDR_ANY→网络字节序)、32 位整数数据(如仿真数值) |
| ntohs() | Network to Host Short(网络→主机,16 位) | 16 位整数 | 接收端口号转换(如 UDP 客户端端口) |
| ntohl() | Network to Host Long(网络→主机,32 位) | 32 位整数 | 接收 IPv4 地址转换、32 位整数数据解析 |
h:Host(主机字节序)。
n:Network(网络字节序,大端)。
s:Short(16 位,对应端口号、16 位数据)。
l:Long(32 位,对应 IPv4 地址、32 位数据)。