网络连接原理:从网线到应用(实践版)
网络连接原理:从网线到应用
不讲 OSI 七层,只讲你真的能用到的。
1. 物理连接:从网线开始
RJ45 与以太网
你的 Mac mini 背后那个网口(或者 USB-C 转网口),插的是 RJ45 网线。这条线里实际有 8 根铜丝,其中 4 根用于信号传输(1-2 发送,3-6 接收),另外 4 根在千兆网络中也会用到。
看看你的网口状态:
# macOS 查看网络接口
networksetup -listallhardwareports
# 查看当前 IP 和连接状态
ifconfig en0
# 关注 inet(IPv4 地址)、ether(MAC 地址)、media(速度,如 autoselect 1000baseT)
# Linux 上更常用
ip link show
ip addr show eth0
# 查看网线是否插好、协商速率
# macOS
system_profiler SPNetworkDataType | grep -A5 "Ethernet"
# Linux
ethtool eth0
# 看 Speed: 1000Mb/s, Duplex: Full, Link detected: yes
MAC 地址
每块网卡出厂时烧录了一个 48 位地址(如 a4:83:e7:2b:1f:3c),这是物理层面的身份标识。MAC 地址只在同一个局域网内有意义,出了路由器就没人看它了。
# 查看本机 MAC
ifconfig en0 | grep ether
# 查看局域网里其他设备的 MAC
arp -a
# 输出类似: ? (192.168.1.1) at aa:bb:cc:dd:ee:ff on en0
# 这就是 ARP 表:IP → MAC 的映射
ARP 协议:IP 到 MAC 的桥梁
你电脑要跟同局域网的设备通信时,它知道的是 IP 地址(如路由器 192.168.1.1),但以太网帧需要 MAC 地址。怎么办?广播大喊:
"谁是 192.168.1.1?请告诉我你的 MAC 地址!"
这就是 ARP 请求。192.168.1.1 回复:“我是,我的 MAC 是 aa:bb:cc:dd:ee:ff。”
实操观察 ARP:
# 清空 ARP 缓存
sudo arp -d -a
# ping 路由器,触发 ARP
ping -c 1 192.168.1.1
# 查看刚学到的 ARP 条目
arp -a | grep 192.168.1.1
用 tcpdump 抓 ARP 包(需要 root):
# macOS
sudo tcpdump -i en0 -n arp
# Linux
sudo tcpdump -i eth0 -n arp
# 你会看到类似:
# ARP, Request who-has 192.168.1.1 tell 192.168.1.5
# ARP, Reply 192.168.1.1 is-at aa:bb:cc:dd:ee:ff
2. IP 与子网:你的电脑怎么知道哪些包该送路由器
IP 地址和子网掩码
ifconfig en0 | grep inet
# inet 192.168.1.5 netmask 0xffffff00 broadcast 192.168.1.255
netmask 0xffffff00 即 255.255.255.0,也就是 /24。
这意味着 192.168.1.0 ~ 192.168.1.255 这 256 个地址是同一个子网。发给这个范围内的包,直接通过 MAC 找对方;发往其他地址的包,送给默认网关(路由器)。
查看路由表:
# macOS
netstat -rn | grep default
# default 192.168.1.1 UGSc en0
# Linux
ip route show
# default via 192.168.1.1 dev eth0
# 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.5
路由表的意思:
- 目标在
192.168.1.0/24→ 直接从eth0发出去 - 其他所有(
default)→ 发给192.168.1.1(路由器)
手动发一个包,追踪它的路径
# 看你的包是怎么一步步走到目标的
traceroute 8.8.8.8
# 或
mtr 8.8.8.8 # 比 traceroute 更好,持续刷新
# 输出类似:
# 1. 192.168.1.1 1ms ← 你的路由器
# 2. 10.0.0.1 3ms ← 运营商第一跳
# 3. 120.36.100.1 5ms ← 运营商骨干
# ...
# N. 8.8.8.8 20ms ← 目标
每一行是一个路由器(hop)。如果有某一跳突然延迟飙升,说明瓶颈在那里。
3. 路由器/NAT:你的私网地址怎么上网的
问题:IPv4 不够用
全球只有约 43 亿个 IPv4 地址,每台设备分一个不可能。解决方案:私网地址 + NAT。
私网地址范围(RFC 1918):
10.0.0.0/8(10.x.x.x)172.16.0.0/12(172.16.x.x ~ 172.31.x.x)192.168.0.0/16(192.168.x.x)
你家所有设备都用 192.168.1.x,这些地址在公网上不可路由。路由器做了 NAT 转换:
内网: 192.168.1.5:5000 → 路由器替换为 → 公网: 120.36.100.5:12345 → 发给 8.8.8.8:443
回包: 8.8.8.8:443 → 到达 120.36.100.5:12345 → 路由器查表替换回 → 192.168.1.5:5000
观察 NAT 连接表(Linux 路由器上):
# 查看当前所有 NAT 映射
sudo conntrack -L
# 输出类似:
# udp 17 30 src=192.168.1.5 dst=8.8.8.8 sport=5000 dport=53 src=8.8.8.8 dst=120.36.100.5 sport=53 dport=12345
# 或者
cat /proc/net/nf_conntrack
每一条就是路由器记忆的映射关系。超时后(通常几十秒到几分钟)自动删除。
NAT 的四种类型
用 iptables 的行为来理解:
Full Cone(完全锥形)
# 映射建立后,任何人都能通过这个映射发进来
iptables -t nat -A POSTROUTING -s 192.168.1.5 -j SNAT --to-source 120.36.100.5:12345
# 只要这条规则在,外部任意 IP 都能往 120.36.100.5:12345 发包,都会转发到 192.168.1.5
特点:映射固定,来者不拒。家用路由器常见。
Restricted Cone(受限锥形)
# 只有 192.168.1.5 主动发过包的目标 IP,才能回包
# 路由器额外记住:允许回包的外部 IP 列表
Port Restricted Cone(端口受限)
# 更严格:不仅要 IP 匹配,端口也要匹配
# 192.168.1.5:5000 → 8.8.8.8:53 建立映射后
# 只有 8.8.8.8:53 能往映射端口发包,8.8.8.8:54 都不行
Symmetric(对称型)
# 同一个内网端口,访问不同目标时分配不同映射端口
# 192.168.1.5:5000 → 8.8.8.8:53 → 映射为 120.36.100.5:10001
# 192.168.1.5:5000 → 9.9.9.9:53 → 映射为 120.36.100.5:10002
用 Linux 模拟 Symmetric NAT:
# Linux 默认的 masquerade 行为接近 Symmetric
# 每个连接独立分配端口
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# 可以用 --random 让端口随机化(更像企业防火墙)
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE --random
4. 端口与协议:TCP vs UDP
端口
IP 地址定位到机器,端口定位到进程。
# 查看哪些端口在监听
# macOS / Linux
ss -tlnp # TCP 监听端口
ss -ulnp # UDP 监听端口
# 或用 lsof(macOS 上更好用)
sudo lsof -i -P | grep LISTEN
TCP:可靠连接
三次握手建立连接,保证数据有序、不丢失。
# 观察 TCP 握手
sudo tcpdump -i en0 -n host 8.8.8.8 and tcp
# 然后另开终端
curl http://8.8.8.8
# 你会看到:
# IP. 192.168.1.5.50000 > 8.8.8.8.80: Flags [S] ← SYN(请求连接)
# IP. 8.8.8.8.80 > 192.168.1.5.50000: Flags [S.] ← SYN-ACK(同意)
# IP. 192.168.1.5.50000 > 8.8.8.8.80: Flags [.] ← ACK(确认)
# ... 然后才是真正的 HTTP 请求
TCP 因为要建立连接、维护状态,NAT 设备跟踪起来比较容易——看到一个 SYN 就知道新连接开始了。
UDP:无连接
发出去就不管了,不保证到达,不保证顺序。但也因为没这些开销,速度快、延迟低。
# 观察 UDP
sudo tcpdump -i en0 -n udp
# DNS 查询就是 UDP 的典型应用
dig google.com
# 你会看到:
# IP 192.168.1.5.50000 > 8.8.8.8.53: UDP, length 40 ← 查询
# IP 8.8.8.8.53 > 192.168.1.5.50000: UDP, length 56 ← 回复
Tailscale/WireGuard 用的是 UDP。因为 VPN 需要低延迟,TCP 套 TCP(你的 VPN 流量本身可能是 TCP,外面再包一层 TCP)会有性能问题。
NAT 对 UDP 的处理比 TCP 麻烦得多——没有握手,没有连接状态,NAT 只能靠”超时”来判断一个映射是否还有效。这也是为什么 UDP 打洞有时间窗口的概念。
5. 打洞原理(STUN / TURN / ICE)
STUN:发现自己的公网映射
STUN 服务器在公网上,你的设备向它发包,它告诉你:“我看到你的源地址是 120.36.100.5:12345”。
# 用 stun-client 实际测试
# macOS
brew install stun
stun stun.l.google.com:19302
# 输出类似:
# Mapped address: 120.36.100.5:12345
# NAT type: Symmetric NAT ← 这里就告诉你 NAT 类型了
打洞过程
A 和 B 都通过 STUN 知道了自己的公网映射
A 把自己的公网地址告诉 B(通过某个信令通道,比如聊天服务器)
B 把自己的公网地址告诉 A
A 往 B 的公网地址猛发 UDP 包
B 往 A 的公网地址猛发 UDP 包
如果 NAT 类型允许(Cone NAT):
A 的 NAT 看到 A 往 B 发过包,允许 B 的回包进入
B 的 NAT 同理
双向通了!直连建立
TURN:打洞失败时的中继
TURN 服务器就是 WebRTC 版的 DERP。两端都连 TURN,TURN 转发数据。
A ←→ TURN 服务器 ←→ B
延迟 = A 到 TURN + TURN 到 B,但至少能通。
ICE:统筹这一切的框架
ICE(Interactive Connectivity Establishment)不是协议,而是一套流程:
- 收集所有候选地址(本地 IP、STUN 探测到的公网映射、TURN 中继地址)
- 按优先级排序(本地 > 公网直连 > TURN 中继)
- 逐个尝试连通性检查
- 选最优的建立连接
用 Tailscale 实际看看你的连接状态:
# 查看当前连接状态
tailscale status
# 输出类似:
# 100.64.0.1 mac-mini linux -
# 100.64.0.2 work-laptop windows -
# \_ via DERP(sfo) ← 走了中继,没建立直连
# 详细查看某个节点的连接信息
tailscale ping --c 5 mac-mini
# pong from mac-mini (100.64.0.1) via DERP(sfo) in 180ms ← 中继
# pong from mac-mini (100.64.0.1) via 120.36.100.5:41641 in 5ms ← 直连!
6. 实战:诊断你的网络
检查你的 NAT 类型
# 方法1: 用 stun
stun stun.l.google.com:19302
# 方法2: 用 Tailscale 自带检测
tailscale netcheck
# 关注:
# UDP: true
# IPv4: 120.36.100.5:12345
# MappingVariesByDestIP: true ← 这个为 true 就是 Symmetric NAT
# DERP latency: ...
抓包分析实际问题
# 抓所有 Tailscale/WireGuard 流量
sudo tcpdump -i any -n udp port 41641
# 41641 是 Tailscale 默认端口
# 抓 DNS 查询
sudo tcpdump -i any -n port 53
# 抓 HTTP 流量(明文)
sudo tcpdump -i any -n port 80 -A
# 抓某个 IP 的所有流量
sudo tcpdump -i any -n host 192.168.1.1
# 保存到文件用 Wireshark 分析
sudo tcpdump -i any -w /tmp/capture.pcap
# 然后用 Wireshark 打开: wireshark /tmp/capture.pcap
测延迟和带宽
# 简单延迟测试
ping -c 10 8.8.8.8
# Tailscale 节点间延迟
tailscale ping --c 10 <节点名>
# 带宽测试
# 在目标机器上启动服务端
iperf3 -s
# 在本机测试
iperf3 -c <目标IP>
# 通过 Tailscale 测试
iperf3 -c 100.64.0.1
mtr 持续追踪路由
# 比 traceroute 好用,持续刷新
mtr -rwzbc 100 8.8.8.8
# 通过 Tailscale IP 追踪(注意:Tailscale 是用户态网络,traceroute 可能不准)
# 但可以测试延迟
mtr -rwzbc 100 100.64.0.1
7. iptables/nftables:Linux 上的防火墙和 NAT
如果你有阿里云 Linux 机器,这些命令会经常用到。
查看当前规则
# 查看所有规则
iptables -L -n -v
# 查看 NAT 规则
iptables -t nat -L -n -v
# 查看规则并显示行号(方便删除)
iptables -L -n --line-numbers
常用操作
# 允许某个端口(如 SSH)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 允许已建立的连接回包
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 默认拒绝其他入站
iptables -P INPUT DROP
# 端口转发:外部访问 8080 转到内网 192.168.1.5:80
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.5:80
iptables -t nat -A POSTROUTING -j MASQUERADE
# 开启 IP 转发(路由器必须)
echo 1 > /proc/sys/net/ipv4/ip_forward
# 永久生效
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
8. Tailscale + 自建 DERP:完整方案
为什么需要自建
Tailscale 默认的 DERP 服务器在海外(东京、旧金山等),中继延迟高。在中国大陆部署一台自己的 DERP,中继流量走国内线路。
在阿里云上部署 DERP
# 1. 安装 Go
wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
# 2. 编译 DERP
go install tailscale.com/cmd/derper@latest
# 3. 运行
sudo ~/go/bin/derper --hostname=your-domain.com --a=:443 --http-port=80 --stun
# 需要 SSL 证书,可以用 Let's Encrypt 或配置 --certmode=manual
# 4. 用 systemd 管理
sudo tee /etc/systemd/system/derper.service << 'EOF'
[Unit]
Description=DERP Server
After=network.target
[Service]
ExecStart=/root/go/bin/derper --hostname=derp.yourdomain.com --a=:443 --stun
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now derper
在 Tailscale 控制台配置
进入 Tailscale Admin Console → DERP Map,添加自定义 DERP 区域:
{
"OmitDefaultRegions": true,
"Regions": {
"900": {
"RegionID": 900,
"RegionCode": "aliyun",
"RegionName": "Aliyun Shanghai",
"Nodes": [{
"Name": "1",
"RegionID": 900,
"HostName": "derp.yourdomain.com",
"DERPPort": 443,
"STUNPort": 3478
}]
}
}
}
验证
# 在 Mac mini 上
tailscale netcheck
# 应该能看到你的自定义 DERP 节点,延迟明显低于海外节点
tailscale ping --c 5 <公司机器>
# 如果显示 via DERP(aliyun),说明走了你的中继
# 如果显示 via IP:port,说明直连成功(更优)
9. 速查表
| 命令 | 用途 |
|---|---|
ifconfig / ip addr | 查看 IP、MAC |
ip route / netstat -rn | 查看路由表 |
arp -a | 查看 ARP 表 |
ping | 测试连通性和延迟 |
traceroute / mtr | 追踪路由路径 |
ss -tlnp | 查看监听端口 |
tcpdump -i any -n <filter> | 抓包分析 |
iptables -L -n -v | 查看防火墙规则 |
conntrack -L | 查看 NAT 连接表 |
tailscale status | Tailscale 节点状态 |
tailscale netcheck | NAT 类型检测 |
tailscale ping | 测试节点间连接方式 |
stun <server> | 检测公网映射和 NAT 类型 |
iperf3 | 带宽测试 |
ethtool | 网卡物理状态 |