网路编程--协议

第一阶段:网络的发展与协议的分层

1. 从"独立模式"到"网络互联"

在网络出现之前,计算机是独立模式(Standalone)的。

  • 场景回顾: 课件中举了一个生动的例子,小松、小竹、小梅三个人要处理不同的业务,但业务数据分别存在不同的终端(A、B、C)上。如果小松要处理业务②,他必须物理移动到终端B面前,而其他人只能等待 1111。
  • 痛点: 效率极低,数据无法共享,资源独占。
  • 解决: 网络互联 的出现解决了这个问题。通过将多台计算机连接在一起,实现了数据共享2。
    • 局域网 (LAN): 通过交换机和路由器连接局部区域内的计算机 3。
    • 广域网 (WAN): 将远隔千里的计算机连接在一起 4。
    • 核心理念: 计算机是人的工具,为了协同工作,网络的产生是必然的 5。
2. 什么是"协议"?(核心概念)

这是网络中最核心的概念。课件中通过"打电话"和"语言"的例子来解释:

  • 通俗理解: 协议就是一种约定6。比如我们打电话,约定响几声接听;或者大家都讲汉语,才能互相听懂。如果一个人讲汉语,另一个人讲葡萄牙语,即便电话线(物理介质)是通的,也无法通信 7。
  • 计算机视角(硬核理解):
    • 计算机传输的是光电信号(0和1)。如果A主机用频率表示0/1,B主机用强弱表示0/1,那就没法聊了 。
    • C++视角下的协议(重点):

所谓协议,本质上就是通信双方都认识的结构化数据类型(Structure。

例子:

假设主机A和主机B在代码中定义了完全相同的结构体:

复制代码
struct protocol {
    int a;
    int b;
    int c;
};

主机A将 struct protocol data = {10, 20, 30}; 发送给主机B 10。

主机B收到一串二进制流,因为它知道这个数据的"协议"(即结构体布局),它就能准确地解析出 a=10, b=20, c=30 11。

    • 标准化的必要性: 因为世界上有不同的硬件厂商(Intel, AMD)、不同的操作系统(Linux, Windows)、不同的网络设备(Cisco, Huawei),如果没有一个统一的标准(协议),大家就乱套了。于是就有了 IEEE, ISO, IETF 等组织来制定标准。
3. 协议分层:解耦合的艺术

协议非常复杂,为了便于维护和实现,必须进行分层

  • 分层的好处: 模块化、解耦合 。
    • 两个人通话,可以分为"语言层"(汉语/英语)和"通信设备层"(电话/无线电)。如果你想把电话换成无线电,不需要改变讲什么语言;如果你想把汉语换成英语,不需要换电话机。这就是分层带来的封装复用
4. OSI七层模型 vs TCP/IP四层模型

这是面试和考试的重灾区,我们需要清晰区分"理论"与"实践"。

|---------------|-------------------------------------|--------------------------------------|
| 模型 | 特点 | 备注 |
| OSI 七层模型 | 逻辑清晰,理论完整,但既复杂又不实用16。 | 包含:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层 17。 |
| TCP/IP 模型 | 工业界的实际标准,通常分为5层或4层(物理层往往被忽略或合并) 18。 | 我们重点学习这个模型。 |

TCP/IP 各层详解与操作系统映射(结合你的 OS 背景):

  1. 应用层 (Application Layer):
    • 职责: 负责应用程序间的沟通 。
    • 协议: HTTP, DNS, FTP, SSH 等 。
    • OS位置:用户空间 (User Space)。这是我们写代码(如你的聊天系统、C#项目)主要打交道的地方。
  1. 传输层 (Transport Layer):
    • 职责: 负责两台主机之间的数据传输,确保数据可靠性(TCP。
    • 协议: TCP, UDP。
    • OS位置:操作系统内核 (Kernel)。无论你的APP是用C++还是Java写的,到了这一层,都是调用操作系统内核的代码 。
  1. 网络层 (Network Layer):
    • 职责: 地址管理和路由选择(规划路径。
    • 协议: IP, ICMP。
    • OS位置:操作系统内核 (Kernel)。它负责在复杂的网络中找到通往目标主机的路。
  1. 数据链路层 (Data Link Layer):
    • 职责: 设备之间的数据帧传送,处理冲突检测、差错校验 。
    • 协议: 以太网协议 (Ethernet)。
    • OS位置:驱动程序 (Driver)。通常由网卡驱动处理 。
  1. 物理层 (Physical Layer):
    • 职责: 负责光/电信号的物理传输(网线、光纤、WiFi电磁波) 。
    • OS位置:硬件 (Hardware)

第二阶段:数据封装、分用与跨网络传输

1. 封装

当你在 C++ 代码中调用 send("你好") 时,这串数据并不是直接飞到对方电脑里的。它需要经过每一层协议的"加持"。

  • 封装的本质: 课件中再次用 C语言结构体 的思维来解释:所谓的"报头"(Header),本质上就是对应协议层的结构体字段 。
    • 报文 (Packet) = 报头 (Header) + 有效载荷 (Payload)
  • 具体流程(自顶向下):
    1. 应用层: 用户数据 "你好" 加上应用层报头。
    2. 传输层: 加上 TCP 或 UDP 报头。在这一层,数据单元被称为 段 (Segment)
    3. 网络层: 加上 IP 报头。在这一层,数据单元被称为 数据报 (Datagram)
    4. 数据链路层: 加上以太网帧头(Ethernet Header)和帧尾。在这一层,数据单元被称为 帧 (Frame)

C++ 视角补充: 在 Linux 内核网络栈(比如你之前关注的 TCP/IP 源码)中,这通常不是真的发生一次又一次的 mallocmemcpy(那样效率太低了)。内核通常使用像 sk_buff 这样的结构,通过移动指针来在数据前面"预留"或"添加"报头空间。

2. MAC 地址通信

数据封装好成了"帧"之后,首先要在局域网 (LAN) 内传播。

  • MAC 地址 (Media Access Control Address):
    • 定义: 类似身份证号,48位(6字节),全球唯一,出厂时烧录在网卡上
    • 作用: 专门用于局域网内识别相连的节点 。
  • 通信原理(广播与碰撞): 一个很有意思的现象:在早期的以太网(或没有交换机环境)中,主机A发消息给主机B,实际上是**"喊"**出来的。
    • 广播: 主机A发出的帧,局域网内的所有主机(C, D, E...)都能收到 。
    • 忽略: 主机C收到后,对比帧头里的 dst: MacB 和自己的 MacC,发现"俺不是MacB",于是丢弃 。
    • 接收: 主机B收到后,发现"俺就是MacB",于是收下处理 。
    • 碰撞域: 如果多台机器同时"喊",就会发生数据碰撞,需要碰撞检测和避免算法(这是底层硬件关心的事)。
3. 数据的"拆快递":分用

当数据到达目标主机后,是一个自底向上 的解包过程,这叫分用

  • 关键问题: 每一层怎么知道要把数据交给上一层的哪个协议?
    • 链路层 -> 网络层: 以太网帧头里有一个字段叫"帧类型",告诉内核是交给 IP 协议还是 ARP 协议 。
    • 网络层 -> 传输层: IP 报头里有一个"协议号"字段,告诉内核是交给 TCP 还是 UDP 。
    • 传输层 -> 应用层: TCP/UDP 报头里有 "端口号",告诉操作系统交给哪个进程(比如 80 给浏览器,QQ的端口给QQ)。
4. 跨网络传输:IP vs MAC (重难点)

这是网络中最容易混淆的概念:既然有了 IP 地址,为什么还要 MAC 地址?

  • 核心区别 :
    • IP 地址: 代表最终目的地 (长远目标)。在传输过程中,源IP和目的IP通常是不变的(暂不考虑NAT)。
    • MAC 地址: 代表下一站 (短期目标)。在传输过程中,每一跳(Hop)都在变
  • 路由器的"换皮"操作: 当数据包经过路由器时,路由器会做以下动作:
    1. 拆包: 拆掉链路层帧头,拿出 IP 数据报。
    2. 路由决策: 看了看目的 IP(是去往另一个局域网的),查路由表,决定下一站发给谁。
    3. 重新封装: 加上的链路层帧头。
      • 新的源 MAC:路由器的 MAC。
      • 新的目的 MAC:下一跳设备的 MAC。
    1. 转发: 发送出去 。

第三阶段:Socket 编程核心与系统接口

1. 为什么有了 IP 还需要端口号?
  • 痛点: IP 地址只能把数据送到主机(比如你的电脑),但这并不是终点 。
    • 你同时开着 Chrome 浏览网页、QQ 聊天、迅雷下载。数据到了你的网卡,操作系统怎么知道这几个包是给 Chrome 的,那几个包是给 QQ 的?
  • 解决: 端口号 (Port)
    • 定义: 2字节(16位)整数,用来在主机上唯一标识一个进程
    • 本质: 端口号是传输层(TCP/UDP)的概念。它就像"分机号"。IP 是公司前台总机,端口号是具体员工的分机。
    • 范围划分 :
      • 0 - 1023: 知名端口(Well-known Ports)。分配给 HTTP (80), SSH (22), FTP (21) 等系统级服务。
      • 1024 - 65535: 动态分配端口。平时写 C++ 或 C# 程序用的都是这些。

C++ 系统视角:

经典面试题:进程 PID 也能唯一标识进程,为什么网络不用 PID 而要专门搞个端口号?

* 解耦合: PID 是操作系统内核进程管理的概念,每次重启程序 PID 都会变。如果网络绑定了 PID,那系统管理和网络协议就强耦合了。端口号提供了一层稳定的逻辑抽象 。

2. 什么是 Socket(套接字)?
  • 公式:IP 地址 + 端口号 = Socket
  • 意义: 互联网上通信的本质,其实是两个进程在通信。
    • {源IP, 源Port, 目的IP, 目的Port} 这样一个四元组,就能在全世界的互联网中唯一标识一条通信通道 。
3. C++ 程序员必须懂的:网络字节序

这是一个涉及内存底层的概念

  • 问题背景:

不同的 CPU 架构对多字节整数的存储顺序不同:

    • 大端 (Big-Endian): 高位字节存放在低地址(符合人类阅读习惯)。
    • 小端 (Little-Endian): 低位字节存放在低地址(x86/x64 架构主流)。
  • 冲突: 如果你的 PC(小端)发一个整数 0x1234abcd 给服务器(可能是大端),服务器如果不转换,读出来的数就完全错了。
  • 规定:网络传输一律采用大端字节序
4 Socket API 与 C 语言的多态:sockaddr

最后是编程接口部分。这里有一个 C 语言实现"多态"的经典设计。

  • 系统调用 (System Calls):

socket, bind, listen, accept, connect。这些函数是你从用户态(User Space)进入内核态(Kernel Space)操作网络协议栈的入口 。

  • 结构体设计的智慧:

Socket API 需要支持多种协议(IPv4, IPv6, Unix Domain Socket)。

    • 通用结构体: struct sockaddr(类似基类)。
    • IPv4 专用: struct sockaddr_in(类似子类)。
    • 实现方式:

这两个结构体的前 16 位都是 AF_INET (地址类型) 。

在调用 bind 或 connect 时,我们将 sockaddr_in* 强制转换为 sockaddr* 传进去。内核读取前 16 位,发现是 AF_INET,就知道剩下的部分该按 IPv4 格式解析

复制代码
// C++ 网络编程常见写法
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(8080); // 注意字节序转换
local.sin_addr.s_addr = htonl(INADDR_ANY);

// 强制类型转换 (C-style polymorphism)
bind(sockfd, (struct sockaddr*)&local, sizeof(local));
相关推荐
少年、潜行2 小时前
F1C100/200S学习笔记(3)-- 裸机开发
linux·笔记·学习·驱动·裸机·f1c200s
虾..2 小时前
Linux 进程池小程序
linux·c++·小程序
北邮刘老师2 小时前
智能体,超越人类与机器的世界“理解者”
网络·人工智能·大模型·智能体·智能体互联网
芥子沫2 小时前
Docker安装Blossom笔记
笔记·docker·容器
UVM_ERROR2 小时前
Git仓库损坏(Segmentation fault)修复实战:虚拟机环境下UVM项目救援指南
笔记·git·vscode·github·芯片
街灯L2 小时前
【Ubuntu】Python uploadserver 文件传输服务器
linux·服务器·ubuntu
苦 涩2 小时前
考研408笔记之计算机组成原理(一)——计算机系统概述
笔记·计算机组成原理·考研408
A13247053122 小时前
SSH远程连接入门:安全高效地管理服务器
linux·运维·服务器·网络·chrome·github
IMPYLH3 小时前
Lua 的 OS(操作系统) 模块
开发语言·笔记·后端·游戏引擎·lua