Skip to main content

网络编程 - IP 路由

这篇文章主要是 Rust 网络编程的第一章阅读记录.

网络地址

需要通过 hosts 和 networks 来可靠地将 packet 传递到目的地.

以太网卡地址(MAC)

也叫做 Media Access Control address. 它是一个 48 bit 长度的唯一 ID, 内置于网络设备中, 用于在 network segment 中识别这个设备. 典型的 MAC 地址是 8 组 2 位的十六进制数, 比如: 01-23-45-67-89-ab-cd-ef(或写作 01:23:45:67:89:ab:cd:ef).

其中有一些位有特殊用途, 比如在 Ethernet frame 中如果需要实现多播, 可以将第一个十六进制数的最低位设置为 1. 而如果是这位设置为 0, 则这个 frame 只会被发送给唯一接收者.

IP 地址

在 IP 网络中设备的唯一地址. IPv4 地址有 32 bit, IPv6 有 128 bit.

如果需要表示一组 IP 地址, 可以使用 CIDR 记法. 比如 192.168.1.0/24, 后面的 24 表示子网掩码的位数是 24, 即表示如下:

  • 子网掩码: 255.255.255.0
  • IP 起始: 192.168.1.0
  • IP 结束: 192.168.1.255
  • IP 段可拥有的总 Host 数: 256

Autonomous system number

较少遇到, 略.

网络通信及端口号

网络通信的两个 host 通常使用 端口号(port number) 来区分彼此间是哪些进程在通信.

当 host A 中有一个进程 ID 为 x 的进程被分配了端口号 p, 则它会将 x(pid) 和 p(port number) 的对应关系记录下来, 当收到发送到该端口号的 IP packet 时, 系统就将数据发送给对应进程.

并且当收到数据时发现对应进程已退出时, 可以将连接关闭(在 TCP 的场景下)并丢弃此 IP packet.

系统中 0 到 1024 端口号被保留给系统自己使用(如果要用, 则需要 root 权限).

IP 路由的运行原理

为理解 IP 路由的运行, 我们首先需要了解 IPV4 地址结构. 我们知道它有 32 位长度(4 字节), 并且实际上它是由网络地址前缀和主机地址构成的. 同时每个网络都有自己保留的广播地址值用于广播(即将消息发送给该网络下所有的 hosts). 网络地址有两大类: 公共和私有. Rust 标准库中提供了方便的方法来区分网络地址类型.

通过子网掩码和实际 IP 计算可以获取该 IP Packet 目标网络和 host, 比如发送给 192.168.122.5/27 的数据包(可知子网掩码是 255.255.255.224)时:

计算出实际网络为 192.168.122.0, 而主机是 0.0.0.5. 接下来就能通过路由表获知应该将包通过哪个接口发送了.

网络中的每个路由器都维护了自己的路由表, 路由表中记录了忘了地址前缀和发送接口的对应关系, 更通俗地说就是 "当一个 packet 需要发送到那个网络时, 需要通过这个接口发送", 而通过这个接口发送到下一个路由时, 该路由可能继续发送, 也可能该路由就是目的地.

同时, 路由表若有多个匹配时, 必须按"最长匹配"原则进行. 比如下面三个接口, 当接到发给 192.168.1.33 的数据包时, 三个网络都可能有这个 IP 地址, 但只有 eth3 满足最长匹配.

IP packet 有 TTL 属性(通常是 64), 表示这个 IP 包最多能被路由多少次, 当走到某个路由发现超过了, 则该 IP packet 会被丢弃. 通过这种机制可以保证 IP Packet 不会因为循环而导致网络阻塞.

DNS 工作原理

通信模型

  • 有连接
  • 无连接

Unix 网络编程接口

基于 Socket 的通信接口, 用于打通用户空间程序和内核网络协议栈.