网络发展
局域网
局域网 是指在有限地理范围内(如一栋建筑、一个校园、一个办公室),将各种计算机、服务器、打印机等设备通过通信线路(路由器)和网络设备连接起来,实现数据通信和资源共享的网络。

特点:
- 覆盖范围小:通常几米到几公里
- 高数据传输率:10 Mbps~100 Gbps
- 低延迟、低误码率
- 所有权归单一组织(私有网络)
广域网
广域网 是指覆盖广阔地理范围(跨越城市、国家甚至大洲)的计算机网络,它连接多个局域网或其它网络,实现远距离的数据通信。

特点:
- 覆盖范围广:几十公里到全球范围
- 数据传输速率相对较低:通常 kbps~Gbps(核心高速,接入层可能较慢)
- 高延迟、相对较高的误码率
- 通常使用电信运营商提供的公共通信线路
- 所有权多为多个组织共享或租用
协议
"协议" 是⼀种约定.
协议本质也是软件,在设计上为了更好的进行模块化,解耦合,也是被设计成为层状结构的
OSI七层模型
第1层:物理层(Physical Layer)
-
功能 :传输原始比特流(0和1),定义物理介质规范
-
关键设备 :集线器(Hub)、中继器、网线、光纤
-
协议/标准:RS-232、V.35、IEEE 802.3(以太网物理层)
-
数据单位:比特(Bit)
-
示例:网线的类型(Cat5/6)、接口形状(RJ45)、电压电平、传输速率
第2层:数据链路层(Data Link Layer)
-
功能:
-
将比特组装成帧,进行差错检测(CRC)
-
物理寻址(MAC地址)
-
流量控制、介质访问控制(MAC子层)
-
-
关键设备 :交换机(Switch)、网桥
-
协议:以太网(IEEE 802.3)、PPP、HDLC、帧中继
-
数据单位 :帧(Frame)
-
重要概念:
-
MAC地址 :48位硬件地址,格式如
00:1A:2B:3C:4D:5E -
交换机:通过MAC地址表进行转发
-
第3层:网络层(Network Layer)
-
功能:
-
逻辑寻址(IP地址)
-
路由选择:确定数据从源到目的地的最佳路径
-
分组转发
-
-
关键设备:路由器(Router)
-
协议 :IP(IPv4/IPv6)、ICMP、ARP、RIP、OSPF、BGP
-
数据单位:数据包/分组(Packet)
-
重要概念:
-
IP地址:32位(IPv4)或128位(IPv6)逻辑地址
-
路由表:路由器用于决定转发路径的表格
-
第4层:传输层(Transport Layer)
-
功能:
-
端到端连接管理
-
可靠传输(确认、重传、排序)
-
流量控制 和拥塞控制
-
多路复用/分解
-
-
协议:TCP(可靠)、UDP(不可靠)
-
数据单位:段(Segment - TCP)/数据报(Datagram - UDP)
-
重要概念:
- 端口号:区分不同应用程序(HTTP:80, HTTPS:443, DNS:53)
第5层:会话层(Session Layer)
-
功能:
-
建立、管理、终止应用程序之间的会话
-
对话控制(全双工/半双工)
-
同步检查点
-
-
示例:RPC(远程过程调用)、SSH会话管理
-
实际应用:断点续传、会话恢复
第6层:表示层(Presentation Layer)
-
功能:
-
数据格式转换(编码、加密、压缩)
-
确保一个系统的应用层数据能被另一个系统理解
-
-
技术示例:
-
加密解密:SSL/TLS(虽然实际在应用层实现)
-
压缩:gzip、ZIP
-
编码转换:ASCII ↔ Unicode、JPEG、MPEG
-
第7层:应用层(Application Layer)
-
功能 :为应用程序提供网络服务接口
-
协议:HTTP、HTTPS、FTP、SMTP、DNS、DHCP、SSH
-
数据单位:消息/数据流
-
注意:用户直接接触的是这一层(浏览器、电子邮件客户端等)
TCP/IP五层(四层)模型

协议的本质
所谓协议,就是通信双方都认识的结构化的数据类型,即结构体。
网络传输基本流程
局域网络传输流程图
局域网通信原理
每台主机在局域网上,要有唯一的标识来保证主机的唯一性:mac地址。

以太网 不是物理实体 ,而是一套由 IEEE 802.3 标准 定义的 通信协议规范。它规定了:
- 帧格式:数据该如何包装(就像信封的书写格式)
- 寻址方式:如何使用 MAC 地址标识设备
- 传输机制:在共享介质上如何避免冲突(CSMA/CD)
- 物理层规范:电缆类型、接口形状、电气信号等
MAC地址
MAC地址 用来识别数据链路层中相连的节点。
- 长度为 48 比特 ,即 6 个字节 。一般用 16 进制数字加上冒号 的形式来表示(例如:08:00:27:03:fb:19)。
- 在网卡出厂时就已经确定,通常不能修改。MAC 地址通常是唯一的(虚拟机中的 MAC 地址不是真实的物理地址,可能会冲突;也有些网卡支持用户配置 MAC 地址)。
- 在以太网中,任何时刻只允许一台机器向网络中发送数据。
- 如果多台机器同时发送,会发生数据干扰,称之为数据碰撞。
- 所有发送数据的主机需要进行碰撞检测 与碰撞避免。
- 在没有交换机的情况下,一个以太网就是一个碰撞域。
- 局域网通信过程中,主机通过目标 MAC 地址判断收到的报文是否是发送给自己的。
这里可以尝试从系统角度来理解局域网通信原理。
同一个网段内的两台主机进行发送消息的过程:

而其中每层都有协议,所以当我进行上述传输流程的时候,要进行封装和解包。

报文=报头+有效载荷

不同协议层对报文有不同的称谓:
-
在传输层 叫做段(segment)
-
在网络层 叫做数据报(datagram)
-
在链路层 叫做帧(frame)
应用层数据通过协议栈发到网络上时,每层协议都会添加一个数据首部 (header),这个过程称为封装(Encapsulation)。
首部中包含了诸如首部长度、载荷长度、上层协议类型等信息。
数据封装成帧后被发送到传输介质上,到达目标主机后,每层协议再依次剥离对应的首部,并根据首部中的 "上层协议字段" 将数据交给相应的上层协议处理。
总结:
各个层的协议:

两台主机通过TCP/IP协议通信过程如下:

在网络传输的过程中,数据不是直接发送给对方主机的,而是先要自定向下将数据交付给下层协议,最后由底层发送,然后由对方主机的底层来进行接受,在自底向上进行向上交付。
数据包封装和分用
完整的数据包封装:

数据包分用:

跨网络传输流程图
IP地址
IP协议有两个版本:IPv4和IPv6。今天主要学习IPv4.
- IP地址是在IP协议中,用来标识网络中不同主机的地址。
- IPv4地址是一个四字节的,32位的整数。
- 用点分隔的每个数字代表一个字节,范围是0-255.
跨网络传输的本质是数据从一台计算机到另一台计算机要经过一个或多个以太网。
源IP地址与目标IP地址:
-
源IP地址 :标识发出数据包的发送主机的网络地址。
-
目标IP地址 :标识数据包在广域网(或互联网)中最终要送达的接收主机的网络地址。
IP地址和Max地址的区别:
- IP地址在整个路由过程中,一直不变
- Mac地址一直在变,Mac地址需要在局域网中找到能去目标IP地址的路径。
- 目标IP地址是一个长远目标,Mac的地址是下一阶段目标,目的IP是路径选择的重要依据,mac地址是局域网转发的重要依据。
Socket编程预备
端口号
两个主机在通信,本质上是两个主机上的进程在互相通信。
一台主机上有很多进程,在网络中我们用不同的端口号来标识不同的进程。
端口号(port) 是传输层协议中的核心概念。
-
端口号是一个 2 字节、16 位 的整数,取值范围为 0 ~ 65535。
-
它的作用是标识主机上的一个进程,告诉操作系统当前收到的数据应当交付给哪一个进程处理。
-
IP 地址 + 端口号 共同唯一标识网络上某一台主机的某一个进程,构成了网络通信的完整端点。
-
在同一时刻,一个端口号只能被一个进程占用(不同协议或不同 IP 可例外,如 TCP 与 UDP 可使用相同端口号)。
端口号范围划分
端口号的范围与用途可分为以下两类:
-
0 ~ 1023 :知名端口号。HTTP、FTP、SSH 等广泛应用的应用层协议,其端口号在此范围内固定分配。
-
1024 ~ 65535 :操作系统动态分配的端口号。客户端程序使用的临时端口通常由此范围分配。
理解源端口号与目的端口
在传输层协议(TCP 与 UDP)的数据段中,包含两个端口号:
-
源端口号:标识发送数据的进程。
-
目的端口号:标识接收数据的进程。
这两个端口号共同描述了 "数据是谁发的,要发给谁",从而实现了主机间进程的准确通信。
理解socket
-
IP 地址用于标识互联网中唯一的一台主机,端口号(port)用于标识该主机上唯一的一个网络进程。
-
IP + Port 即可表示互联网中唯一的一个进程。
-
网络通信的本质就是进程间通信。
-
我们将 IP + Port 的组合称为 套接字(Socket)。
传输层的典型代表
网络协议栈:网络协议栈 (Network Protocol Stack)是指网络通信中一组按照分层结构组织的协议集合。它定义了数据如何在不同层次上封装、传输和解封装,确保不同设备、不同系统之间能够可靠、有序地进行通信。

TCP协议
TCP ( Transmission Control Protocol 传输控制协议)的特点:
- 传输层协议
- 有连接
- 可靠传输。用户发送消息后消息有什么"事故",该协议都包售后。
- 面向字节流
字节流 是一种数据传输模型,数据像水流 一样以连续的字节序列 形式传输,没有固定的消息边界。即不知道读取到哪个地方,比如"hello world"发送方把这两个单词分别发送,但是接收方同时接到的是两个单词。
UDP协议
UDP ( User Datagram Protocol 用户数据报协议)的特点:
- 传输层协议
- 无连接
- 不可靠传输。不包售后,只管发,不管后续。
- 面向数据报(网络层报文)
数据报会完完整整的读取和发送一句话。有明确的边界,发送方写多少,接收方就接收多少,不会粘在一起。
网络字节序(大小端)
假设一个 32位整数0x12345678(十六进制):
-
大端序存储内存地址:0x12 | 0x34 | 0x45 | 0x78 (从左往右读)
-
小端序存储内存地址:0x78 | 0x45 | 0x34 | 0x12 (从右往左读)
网络数据流的字节序应遵循以下规定:
-
TCP/IP 协议规定 :网络数据流应采用大端字节序,即低地址存放高位字节。
-
无论主机本身是大端机还是小端机,都必须按照 TCP/IP 规定的网络字节序发送和接收数据。
-
如果发送主机是小端机 ,则需要先将数据转换为大端序 再发送;如果发送主机本身就是大端机,则可直接发送。
为使网络程序具有良好的可移植性,确保同样的 C 代码在大端和小端计算机上都能正确运行,可以调用以下库函数进行网络字节序与主机字节序之间的转换。
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);//IP地址:主机转网络
uint16_t htons(uint16_t hostshort);//端口号:主机转网络
uint32_t ntohl(uint32_t netlong);//IP地址:网络转主机
uint16_t ntohs(uint16_t netshort);//端口号:网络转主机
注:所有发送到网络上的数据,都必须是大端的!
socket编程接口
socket 常见API(应用程序编程接口)
// 创建 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);
sockadddr结构
- IPv4 和 IPv6 的地址格式定义在 <netinet/in.h> 头文件中。
- IPv4 地址使用 sockaddr_in结构体表示,包含 16 位地址类型、16 位端口号和 32 位 IP 地址。
- IPv4 和 IPv6 的地址类型分别定义为常量"AF_INET"和 "AF_INET6"。
- 这样,只要取得某种 sockaddr 结构体的首地址,即使不知道具体是哪种类型的 sockaddr, 也可以根据地址类型字段确定结构体中的内容。
- Socket API 均使用 struct sockaddr *类型表示,使用时需要强制转换为 sockaddr_in等具体类型。
这样做的好处是提高程序的通用性,可以接收 IPv4、IPv6 以及 UNIX Domain Socket 等各种类型的sockaddr 结构体指针作为参数。

注:UNIX Domain Socket(本地进程间通信)用:sockaddr_un结构体,地址类型定义为AF_UNIX / AF_LOCAL。
IPV4结构体定义示例:
struct sockaddr_in {
sa_family_t sin_family; // 地址族:AF_INET 即地址类型
in_port_t sin_port; // 端口号
struct in_addr sin_addr; // IPv4地址 ← 就是这里
char sin_zero[8]; // 填充字段(通常置零)
};
sin_addr结构体定义示例:
// 定义在 <netinet/in.h> 中
struct in_addr {
in_addr_t s_addr; // 32位的IPv4地址(网络字节序)
};
注:sin_addr存放 IPv4地址二进制形式 的结构体成员,使用时一定要注意字节序转换
ip地址字符串转换成网络字节序的函数:
//将 点分十进制IPv4地址字符串 转换为 32位网络字节序整数
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
参数:cp - 点分十进制IPv4地址字符串(如 "192.168.1.1")
htonl和inet_addr函数的区别:
htonl :转变的是:主机字节序整数uint32_t(整数) → 网络字节序整数uint32_t(整数)
inet_addr:转变的是:点分十进制字符串 const char*(字符串)→ 网络字节序整数 in_addr_t(整数)