计算机系统基础-07:网络
网络
网络主机
多数网络应用基于 Client-Server 模型。一个 server 进程管理某类资源,client 进程通过请求让 server 对资源执行操作,然后接收响应。Client 和 server 都是运行在主机上的进程,可以位于同一台主机,也可以位于不同主机。

网络主机由 CPU、主存、I/O bridge、I/O bus、磁盘控制器、图形适配器、USB 控制器和 network adapter 等部件组成。网络适配器连接主机与网络,协议软件运行在内核与用户程序之间,负责把用户数据封装为网络帧并交给硬件发送。

从程序员视角看,网络 I/O 最终通过描述符读写;从硬件视角看,网络数据经由 network adapter 进入主机,再通过中断、DMA 等机制交给操作系统处理。
局域网与 Ethernet
计算机网络是按地理邻近性组织的层次系统,由通信链路和网络设备构成。底层通常是 LAN(Local Area Network),覆盖一个房间、楼层、建筑或校园。常见 LAN 技术是 Ethernet。
Ethernet segment 由主机、双绞线和 switch 组成。主机发送的数据按 frame 传输:
1 | Ethernet frame = frame header + payload |
Frame header 至少包含:
- 源 MAC 地址。
- 目的 MAC 地址。
- frame 长度等控制信息。
每块 Ethernet adapter 有唯一 48-bit MAC 地址,例如 00:16:ea:e3:54:e6。
switch 如何区分发送方和接收方?
Switch 使用 MAC 地址。发送 frame 时,frame header 中包含 source MAC 和 destination MAC。Switch 根据 destination MAC 决定转发端口。
switch 如何构造 MAC table?
Switch 可通过 source MAC 学习端口映射。若从端口 1 收到源地址为
Mac-A的 frame,就记录Mac-A -> port 1。后续收到目的地址为Mac-A的 frame 时,可直接转发到端口 1。
如果 switch 尚未建立可用的 MAC table,仍可通过广播方式转发 frame:把收到的 frame 发到除入口外的其他端口,由各主机检查 destination MAC 是否匹配自己。该方法能工作,但会增加无关主机收到的 frame 数量,效率较低。MAC table 的作用是把广播式转发优化为定向转发。
只用 MAC 地址能否支撑大规模网络?
不适合。MAC 地址是网卡制造时确定的平面标识,不体现网络位置。若网络规模达到较多主机,路由设备难以用平面 MAC 地址表完成可扩展转发。因此需要具有层次结构的网络地址,即 IP 地址。
IP 地址在主机接入网络时由网络配置分配,能反映当前所在网络的前缀;MAC 地址随网卡固定,不随物理位置变化。路由器可以按 IP 前缀聚合路由项,而不必记录每个网卡的全局位置。
子网、IP 地址与路由
网络规模达到较多主机,路由设备难以用平面 MAC 地址表完成可扩展转发,因此需要进行划分。IP 地址用于描述主机在网络层的位置。处于同一 subnet 的主机通常具有相同地址前缀,例如:
1 | 202.120.40.1 |

路由器根据 IP 地址前缀转发 packet。Subnet 使 routing table 可按前缀聚合,避免为每台主机维护独立路由。
MAC 地址和 IP 地址的分工:
| 地址 | 层次 | 作用 |
|---|---|---|
| MAC address | 数据链路层 | 标识同一链路上的网卡 |
| IP address | 网络层 | 标识主机或路由接口在 IP 网络中的位置 |
发送数据时,IP header 描述端到端的源 IP 和目的 IP;MAC header 描述当前链路上的下一跳。
同子网与跨子网转发
设主机 A 为 202.120.40.1 / Mac-A,主机 C 为 202.120.40.2 / Mac-C,主机 X 为 202.120.41.1 / Mac-X,路由器在 A 所在子网的接口为 202.120.40.255 / Mac-R1,在 X 所在子网的接口为 202.120.41.255 / Mac-R2。

A 发送给同子网主机 C
A 使用子网掩码判断 C 与自己在同一子网。Frame 的目的 MAC 是 C 的 MAC。
1 | Mac Header: Src = Mac-A, Dst = Mac-C |
A 发送给跨子网主机 X
A 使用子网掩码判断 X 不在本子网,因此把 frame 发给默认网关。第一跳目的 MAC 是路由器接口 Mac-R1,但 IP header 的目的 IP 仍是 X。
1 | Host A -> Router R1 |
- IP header 在端到端路径上保持源 IP 和目的 IP。
- MAC header 只在单条链路上有效,每经过一个 router 都会更新。
- 主机通过 subnet mask 判断目的主机是否在本子网。
- 主机通过 gateway 找到跨子网转发的下一跳。
应用只给出目的 IP,如何得到下一跳 MAC?
使用 ARP(Address Resolution Protocol)。在同一链路内,主机可通过 ARP 查询某个 IP 对应的 MAC 地址。若目的 IP 不在本子网,则查询 gateway IP 对应的 MAC 地址。
ARP 的基本流程:发送方在本子网广播“谁拥有某个 IP”,拥有该 IP 的主机返回自己的 MAC 地址。发送方记录
IP -> MAC映射后,再构造 Ethernet frame。ARP 只能在本链路广播范围内解析地址,因此跨子网时解析的是下一跳 gateway 的 MAC,而不是最终目的主机的 MAC。
Internet Protocol
多个 LAN 可通过 router 连接成 internet。IP 协议提供两个核心功能:

- 命名机制:定义统一的 host address 格式。
- 传输机制:定义标准传输单元 packet。
IP packet 由 header 和 payload 组成:
1 | IP packet = IP header + payload |
IP header 包含 packet 大小、源地址、目的地址等信息。Payload 存放上层协议数据。
在不同 LAN 之间转发时,IP packet 会被封装进当前 LAN 的 frame 中。Router 收到 frame 后去掉当前链路层 header,根据 IP header 查路由,再封装为下一条链路的 frame。

1 | Host A --LAN1 frame--> Router --LAN2 frame--> Host B |
NAT
IPv4 地址为 32 位,地址数量有限。局域网常使用私有地址,例如 192.168.1.10。不同局域网可以使用相同私有地址,因为这些地址不直接作为公网唯一地址使用。
NAT(Network Address Translation)在私有地址和公网地址之间转换。
SNAT
SNAT 修改 packet 的 source address,常用于内网主机访问公网。

1 | Before NAT: |
NAT 设备维护映射表:
| Local | Global |
|---|---|
192.168.1.10:10086 |
202.120.40.82:233 |
192.168.1.11:10086 |
202.120.40.82:234 |
返回 packet 到达 NAT 设备后,NAT 根据 global port 找回 local address 和 local port。
DNAT
DNAT 修改 packet 的 destination address,常用于把内网服务暴露给公网。

| Public port | Local service |
|---|---|
8080 |
192.168.1.10:10086 |
公网访问 202.120.40.82:8080 时,NAT 可把目的地址改写为 192.168.1.10:10086。
协议栈
TCP/IP 协议族是 Global IP Internet 的基础。

| 协议 | 基于 | 提供的抽象 |
|---|---|---|
| UDP | IP | 不可靠 datagram,从进程到进程 |
| TCP | IP | 可靠 byte stream,从进程到进程 |
应用通过 Berkeley sockets interface 访问网络。Socket I/O 与 Unix file I/O 使用相同的描述符抽象,区别在于 socket descriptor 的打开方式不同。

可把网络协议栈理解为四层:
| 层次 | 主要内容 | 作用 |
|---|---|---|
| Link layer | Ethernet、MAC、switch | 在同一链路或局域网内传 frame |
| Network layer | IP、router | 通过 IP 地址和路由完成 host-to-host delivery |
| Transport layer | TCP、UDP | 在进程之间提供传输抽象 |
| Application layer | HTTP、FTP、SMTP 等 | 由应用约定 request/response 的格式和语义 |
IP 只提供命名和尽力而为的转发。TCP 在 IP 之上处理丢包、乱序和重传,为应用提供可靠、有序的 byte stream;UDP 更轻量,不提供同等可靠性保证,应用可自行处理丢包和顺序问题。
程序员视角下的 Internet
程序员通常使用三类标识:
- 32-bit IP address,例如
0xca7828bc。 - Domain name,例如
ipads.se.sjtu.edu.cn。 - Socket address,即
IP address:port。
IP 地址通常写为 dotted decimal notation。每个字节转为十进制并用点分隔,例如:
1 | 0xca7828bc = 202.120.40.188 |
IP 地址在内存中按 network byte order 存储,即 big-endian byte order。
DNS
DNS(Domain Name System)是在 Internet 中维护 domain name 与 IP address 映射的分布式数据库。
DNS host entry 可视为 domain name 和 IP address 的等价类。常见映射关系包括:

| 类型 | 含义 | 示例 |
|---|---|---|
| 1-1 | 一个域名对应一个 IP | whaleshark.ics.cs.cmu.edu -> 128.2.210.175 |
| M-1 | 多个域名对应同一 IP | cs.mit.edu 与 eecs.mit.edu 可对应同一 IP |
| M-N | 多个域名对应多个 IP | twitter.com 和 www.twitter.com 可对应多个地址 |
Client 若只知道 domain name,通常先通过 DNS 得到 server IP,再发起连接。
Internet Connection
TCP connection 是两个进程之间的通信通道,具有以下性质:
- point-to-point:连接一对进程。
- full-duplex:两个方向可同时传输数据。
- reliable:源进程发送的数据最终按发送顺序到达目的进程。
Socket 是连接的端点。Socket address 由 IP address 和 port 组成:
1 | socket address = IP address : port |
Port 是 16-bit 整数,用于标识主机上的进程或服务。Client port 通常是系统自动分配的 ephemeral port;server port 通常是 well-known port,例如 Web server 使用 port 80,SMTP 使用 port 25。
一条连接由两个端点唯一确定:

Client-Server 通信
Socket 接口
Client 和 server 通过 socket descriptor 使用 Unix I/O 读写网络。

封装函数:
open_clientfd(host, port):client 端创建连接。open_listenfd(port):server 端创建监听描述符。
通信流程:
flowchart TD
subgraph Client[客户端 Client]
C1[getaddrinfo<br/>获取服务器地址信息]
C2[socket<br/>创建客户端套接字]
C3[connect<br/>向服务器发起连接请求]
C4[writen<br/>发送请求数据]
C5[readline<br/>读取服务器响应]
C6{是否继续通信?}
C7[close<br/>关闭连接]
end
subgraph Server[服务器 Server]
S1[getaddrinfo<br/>获取本机监听地址信息]
S2[socket<br/>创建监听套接字]
S3[bind<br/>绑定 IP 和端口]
S4[listen<br/>进入监听状态]
S5[accept<br/>等待并接受客户端连接]
S6[readline<br/>读取客户端请求]
S7[writen<br/>发送响应数据]
S8{客户端是否关闭?}
S9[readline 读到 EOF]
S10[close<br/>关闭本次连接]
end
C1 --> C2 --> C3
S1 --> S2 --> S3 --> S4 --> S5
C3 -- connection request --> S5
S5 --> S6
C3 --> C4
C4 -- 请求数据 --> S6
S6 --> S7
S7 -- 响应数据 --> C5
C5 --> C6
C6 -- 是 --> C4
C6 -- 否 --> C7
C7 -- EOF --> S9
S8 -->|是| S9
S9 --> S10
S10 --> S5
Echo Client
Echo client 从标准输入读取一行,写入 server,再读取 server 返回并输出。
1 | int main(int argc, char **argv) |
open_clientfd 的核心步骤:
- 用
getaddrinfo(hostname, port, &hints, &listp)取得候选 server address。 - 遍历候选 address。
- 对每个 address 调用
socket创建 socket descriptor。 - 调用
connect连接 server。 - 若连接失败,关闭 descriptor 并尝试下一个 address。
1 | /* 创建 socket,协议族、socket 类型和协议参数来自 getaddrinfo 结果。 */ |
connect 会阻塞 client,直到连接建立或失败。连接建立后,client 可对 clientfd 使用普通 Unix I/O。
getaddrinfo 中常见 flag:
| flag | 作用 |
|---|---|
AI_NUMERICSERV |
要求 service 参数是数字端口 |
AI_ADDRCONFIG |
按本机网络配置返回 IPv4 / IPv6 地址 |
Echo Server
Iterative echo server 的主循环:
1 | int main(int argc, char **argv) |
Server 使用两个不同的 descriptor:
| descriptor | 含义 |
|---|---|
listenfd |
listening descriptor,用于接收连接请求 |
connfd |
connected descriptor,用于和某个 client 通信 |

open_listenfd 的核心步骤:
getaddrinfo(NULL, port, &hints, &listp)取得可用于监听的本机地址。AI_PASSIVE表示返回 server listening socket 可绑定的地址。socket创建 descriptor。setsockopt(..., SO_REUSEADDR, ...)避免重启 server 时常见的Address already in use。bind把 socket descriptor 绑定到地址和端口。listen把 descriptor 转为 listening socket。- 主循环中调用
accept等待连接请求。
1 | /* 将监听 socket 绑定到本地 IP/端口。 */ |
listen 的 backlog 参数提示内核可排队的未完成连接请求数量。accept 阻塞等待连接请求,成功后返回 connected descriptor,并填充 client address。
为什么
accept返回的通常不是listenfd?
listenfd只负责监听连接请求,可以长期存在并被反复传给accept。一次accept成功后,内核会新建一个 connected descriptor,例如普通进程已占用0/1/2,open_listenfd得到listenfd = 3,第一次accept常返回最低空闲描述符4。后续读写 client 数据应使用
connfd,不能使用listenfd。listenfd留给 server 主循环继续接收新的连接请求;connfd表示本次 TCP connection 的一个端点。
Echo 函数用 Robust I/O 逐行读取,直到遇到 EOF:
1 | void echo(int connfd) |
EOF 是连接状态,不是一个数据字节。通常由 client 调用 close(clientfd) 触发。
HTTP
Web 事务流程
HTTP(HyperText Transfer Protocol)运行在 TCP 之上。典型 Web 事务流程:
- Client 和 server 建立 TCP connection。
- Client 发送 HTTP request。
- Server 返回 HTTP response 和 content。
- 双方关闭连接或复用连接。
1 | IP -> datagrams |
HTTP response 返回的 content 是字节序列,并带有 MIME type。
常见 MIME type:
| MIME type | 内容 |
|---|---|
text/html |
HTML page |
text/plain |
plain text |
application/postscript |
PostScript document |
image/gif |
GIF image |
image/jpg |
JPG image |
Web content 可分为:
- static content:存储在文件中,请求到达时读取文件返回,例如 HTML、图片、音频。
- dynamic content:请求到达时由 server 执行程序生成,例如 CGI 程序。
URL
URL(Uniform Resource Locator)标识 server 管理的资源。
静态内容示例:
1
2 http://ipads.se.sjtu.edu.cn:80/courses/ics/index.shtml
http://ipads.se.sjtu.edu.cn/courses/ics/动态内容示例:
1 http://www.cs.cmu.edu:8000/cgi-bin/adder?15000&213
Client 使用 URL prefix 推断:
- 使用何种协议,例如 HTTP。
- Server 域名或 IP。
- Server port,例如 80。
Server 使用 URL suffix 判断请求资源:
- 是否为 static content 或 dynamic content。
- 文件系统路径。
- 若 suffix 为
/,通常扩展到默认主页,例如index.html。
约定上,动态可执行程序常放在 cgi-bin 目录中。
HTTP Request
HTTP request 由 request line、若干 request header 和空行组成:
1 | <method> <uri> <version> |
示例:
1
2
3 GET /courses/ics/index.shtml HTTP/1.1
host: ipads.se.sjtu.edu.cn
字段含义:
| 字段 | 含义 |
|---|---|
method |
请求方法,例如 GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE |
uri |
资源标识;对 proxy 常是完整 URL,对 server 常是 URL suffix |
version |
HTTP 版本,例如 HTTP/1.0 或 HTTP/1.1 |
常见方法:
GET:获取 static 或 dynamic content。动态参数通常放在 URI 中。POST:把参数放在 request body 中,请 server 接收并处理。
HTTP/1.1 请求通常需要 Host header。
HTTP Response
HTTP response 由 response line、若干 response header、空行和 response body 组成:
1 | HTTP/1.1 200 OK |
Response line 格式:
1 | <version> <status code> <status msg> |
常见状态码:
| 状态码 | 含义 |
|---|---|
200 OK |
请求成功 |
301 Moved |
提供替代 URL |
403 Forbidden |
server 没有权限访问该文件 |
404 Not Found |
server 找不到该文件 |
501 Not Implemented |
server 不支持该 request method |
505 HTTP Version Not Supported |
server 不支持该 HTTP 版本 |
常见 response header:
Content-Type:response body 的 MIME type。Content-Length:response body 的字节长度。
HTTP 事务示例:
可用
telnet手工发起 HTTP 请求:
1
2
3
4
5
6
7
8 unix> telnet ipads.se.sjtu.edu.cn 80
Trying 202.120.40.85...
Connected to ipads.se.sjtu.edu.cn.
Escape character is '^]'.
GET /courses/ics/index.shtml HTTP/1.1
host: ipads.se.sjtu.edu.cn流程解析:
telnet建立到ipads.se.sjtu.edu.cn:80的 TCP connection。- Client 输入 request line。
- Client 输入
Hostheader。- 空行结束 request header。
- Server 返回 response line、headers、空行和 body。

