FAQ-3:网络与连接常见问题

预计阅读时间:12 分钟

📖 目录

FAQ-3:网络与连接常见问题(Q29-Q43)

问题速查表

问题章节
Q29: 如何查看哪些进程在监听端口?Q29
Q30: 端口被占用怎么办?Q30
Q31: 如何测试远程端口是否开放?Q31
Q32: 如何查看网卡速率?Q32
Q33: curl SSL 证书错误?Q33
Q34: 如何配置静态 IP(Netplan)?Q34
Q35: 如何查看当前连接数?Q35
Q36: SSH 连接自动断开?Q36
Q37: 如何实现 SSH 免密登录?Q37
Q38: 如何查看 DNS 解析过程?Q38
Q39: 如何限制某 IP 访问?Q39
Q40: 为什么 ping 不通但端口是通的?Q40
Q41: 如何设置 HTTP 代理?Q41
Q42: 如何抓取 HTTP 请求响应?Q42
Q43: scp 传输中断了怎么办?Q43

Q29: 如何查看哪些进程在监听端口?

当服务启动失败或端口冲突时,第一步是确认哪些进程占用了端口。

# ss -tlnp:查看 TCP 监听端口
# -t:TCP  -l:listening(监听中)  -n:数字显示(不解析域名)  -p:显示进程
ss -tlnp

# ss -tulnp:同时查看 TCP 和 UDP
ss -tulnp

# lsof -i :80:查看占用 80 端口的进程
lsof -i :80

# 预期输出示例:
# State  Recv-Q  Send-Q  Local Address:Port  Peer Address:Port  Process
# LISTEN 0       128     0.0.0.0:80          0.0.0.0:*          users:(("nginx",pid=1234,fd=6))

Q30: 端口被占用怎么办?

启动服务时提示 Address already in use,说明端口已被其他进程占用。

# 第一步:找到占用端口的进程
ss -tlnp | grep :8080
# 输出:LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=5678,...))

# 第二步:终止占用进程(或修改自己的应用端口)
sudo kill 5678        # 发送 SIGTERM(优雅终止)
sudo kill -9 5678     # 强制终止(仅在 SIGTERM 无效时使用)

# 或者修改应用配置,使用其他端口

Q31: 如何测试远程端口是否开放?

# nc(netcat):网络瑞士军刀
# -z:只扫描不发送数据
# -v:详细输出
nc -zv 192.168.1.100 80

# Bash 内置方式(无需安装额外工具)
# /dev/tcp 是 Bash 的特殊设备,成功连接会返回 0
timeout 3 bash -c "

Q32: 如何查看网卡速率?

# ethtool:查看网卡物理参数(速率、双工模式等)
ethtool eth0 | grep Speed
# 输出:Speed: 1000Mb/s

# ip -s link:查看网卡统计信息(收发包数、错误数)
ip -s link show eth0

Q33: curl SSL 证书错误?

SSL 证书错误常见原因:自签名证书、证书过期、系统时间不正确、证书链不完整。

# 跳过证书验证(仅用于测试,生产环境不要用)
curl -k https://example.com

# 查看证书详细信息
curl -vI https://example.com 2>&1 | grep -E "expire|subject|issuer"

# 检查系统时间(证书验证依赖时间)
date

Q34: 如何配置静态 IP(Netplan)?

Netplan 是 Ubuntu 18.04+ 的网络配置工具,通过 YAML 文件定义网络参数。

# 编辑配置文件(注意 YAML 缩进,用空格不用 Tab)
sudo vim /etc/netplan/01-netcfg.yaml

# 示例配置:
network:
  version: 2
  ethernets:
    eth0:
      addresses:
        - 192.168.1.100/24          # 静态 IP 地址
      routes:
        - to: default
          via: 192.168.1.1          # 默认网关
      nameservers:
        addresses:
          - 8.8.8.8                 # DNS 服务器
          - 114.114.114.114

# 应用配置(会短暂断开网络连接)
sudo netplan apply

# 调试语法错误
sudo netplan --debug generate

Q35: 如何查看当前连接数?

# ss -s:连接状态汇总
ss -s

# 统计已建立的 TCP 连接数
ss -tan state established | wc -l

# 按状态统计
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
# 输出示例:
#   150 ESTAB
#    20 TIME-WAIT
#     5 LISTEN

Q36: SSH 连接自动断开?

长时间空闲的 SSH 连接会被防火墙或 NAT 网关中断。通过 keepalive 机制保持连接。

# 服务端配置(/etc/ssh/sshd_config)
# 每 60 秒向客户端发送 keepalive 探测
ClientAliveInterval 60
ClientAliveCountMax 3    # 3 次无响应才断开

# 客户端配置(~/.ssh/config)
# 每 60 秒向服务端发送 keepalive
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

# 修改后重启 SSH 服务(仅服务端需要)
sudo systemctl restart sshd

Q37: 如何实现 SSH 免密登录?

基于密钥的 SSH 认证比密码更安全且更方便。

# 1. 生成密钥对(ed25519 是当前推荐算法)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 默认保存到 ~/.ssh/id_ed25519(私钥)和 ~/.ssh/id_ed25519.pub(公钥)

# 2. 将公钥复制到目标服务器
ssh-copy-id user@host
# 会自动将公钥追加到目标服务器的 ~/.ssh/authorized_keys

# 3. 测试免密登录
ssh user@host    # 不再需要输入密码

Q38: 如何查看 DNS 解析过程?

# dig +trace:显示完整的 DNS 解析链路
# 从根服务器开始,逐级查询到最终结果
dig +trace example.com

# 简单查询
dig example.com

# 指定 DNS 服务器查询
dig @8.8.8.8 example.com

Q39: 如何限制某 IP 访问?

# ufw(Ubuntu 默认防火墙)
sudo ufw deny from 1.2.3.4

# iptables(通用方式)
# -A INPUT:追加到 INPUT 链
# -s 1.2.3.4:源地址
# -j DROP:直接丢弃(不回复)
sudo iptables -A INPUT -s 1.2.3.4 -j DROP

# nftables(iptables 的继任者,推荐)
sudo nft add rule inet filter input ip saddr 1.2.3.4 drop

Q40: 为什么 ping 不通但端口是通的?

ping 使用 ICMP 协议,而端口连接使用 TCP/UDP 协议。防火墙可以单独禁 ICMP 而放行 TCP。ICMP 和 TCP 是网络协议栈中不同层级的协议,防火墙规则可以独立控制每一层。

# ping 使用 ICMP 协议(第 3 层)
# curl/nc 使用 TCP 协议(第 4 层)
# 两者互不影响

# 验证:用 TCP 方式测试
nc -zv 192.168.1.100 80
curl http://192.168.1.100:80

# 如果需要允许 ping(ICMP)
sudo ufw allow icmp
# 或 iptables:
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

Q41: 如何设置 HTTP 代理?

# 临时设置(仅当前终端生效)
export http_proxy=http://proxy.example.com:8080
export https_proxy=http://proxy.example.com:8080
export no_proxy=localhost,127.0.0.1    # 不走代理的地址

# 永久设置(写入 ~/.bashrc)
echo 'export http_proxy=http://proxy.example.com:8080' >> ~/.bashrc
echo 'export https_proxy=http://proxy.example.com:8080' >> ~/.bashrc

Q42: 如何抓取 HTTP 请求响应?

# tcpdump:底层抓包工具
# -i any:监听所有网卡
# -A:以 ASCII 显示包内容
# port 80:只抓 80 端口
sudo tcpdump -i any -A port 80

# curl -v:显示详细的请求/响应头信息
curl -v https://example.com

Q43: scp 传输中断了怎么办?

scp 不支持断点续传,中断后只能重传。rsync 支持断点续传和增量同步。

# rsync 替代 scp(支持断点续传)
# -a:归档模式(保留权限、时间戳)
# -v:详细输出
# -z:传输时压缩
# --partial:保留部分传输的文件(断点续传的关键)
# --progress:显示传输进度
rsync -avz --partial --progress large_file user@host:/path/

真实案例

案例 A:服务绑定 127.0.0.1 导致外部无法访问

现象:Node.js 应用在服务器上 curl localhost:3080 正常,但浏览器访问 http://服务器IP:3080 始终连接超时。

# 服务器本机测试正常
$ curl http://localhost:3080
{"status":"ok"}

# 远程客户端测试失败
$ curl -v http://10.0.0.5:3080
* connect to 10.0.0.5 port 3080 failed: Connection refused

# 查看监听地址
$ ss -tlnp | grep 3080
LISTEN 0 128 127.0.0.1:3080 0.0.0.0:* users:(("node",pid=1823,...))

根因:应用监听地址为 127.0.0.1(回环接口),只有本机能访问。

修复:将监听地址改为 0.0.0.0(所有接口)或具体网卡 IP。

案例 B:防火墙 REJECT 与服务未启动的 Connection refused 区分

现象:两台服务器 A 访问 B 的 3306 端口报 Connection refused,但原因不同——一个是防火墙拒绝,一个是服务没启动。

# 测试一:服务在监听,但防火墙 REJECT
$ nc -zv 10.0.0.11 3306
Connection refused
$ ss -tlnp | grep 3306
LISTEN 0 70 0.0.0.0:3306 ...      # 服务活着

# 测试二:服务根本没启动
$ nc -zv 10.0.0.11 3306
Connection refused
$ ss -tlnp | grep 3306            # 无输出

区分方法Connection refused 只说明"被拒绝",可能是服务未启动,也可能是防火墙 REJECT。必须先在服务端执行 ss -tlnp 确认端口是否在监听,再查防火墙规则。Connection timed out 才表示被 DROP(丢弃)。

案例 C:Netplan YAML 缩进错误导致网络断连

现象:修改 Netplan 配置后执行 sudo netplan apply,SSH 立即断开,无法重新连接。

# 错误配置(用 Tab 缩进而非空格)
network:
	ethernets:        # ← Tab 缩进,Netplan 不识别
	  eth0:
	    addresses: [192.168.1.100/24]

根因:Netplan 使用 YAML 格式,YAML 严格要求用空格缩进(不能用 Tab)。Tab 缩进导致语法解析失败,网络配置应用失败,网卡未获得 IP。

修复:连接控制台(或物理访问),将 Tab 替换为空格,重新 netplan apply。预防:Netplan 修改前用 sudo netplan --debug generate 验证语法。

预防措施

  • 部署服务后立即用 ss -tlnp | grep 端口号 确认监听地址是否正确
  • 配置 SSH keepalive(ServerAliveInterval 60)避免长时间空闲连接被中断
  • 大文件传输用 rsync --partial 替代 scp,支持断点续传
  • Netplan 修改前先用 netplan --debug generate 检查语法,避免网络配置错误导致无法 SSH
  • DNS 解析异常时先用 dig +trace 排查,确认是本地 DNS 还是上游服务器问题
  • 防火墙规则变更前用 nc -zv 做连通性测试,变更后立即验证
  • 生产环境 SSH 配置 MaxAuthTries 3 防暴力破解,配合 fail2ban 自动封禁
  • 大文件传输优先用 rsync --partial --progress,支持断点续传和进度显示
  • Netplan 修改前用 sudo netplan try 测试配置,超时自动回滚避免网络断连
  • DNS 解析异常时先用 dig +trace 排查,确认是本地 DNS 还是上游服务器问题

案例 D:服务只监听 IPv6 导致 IPv4 客户端无法连接

现象:新安装的 Nginx 默认只监听 IPv6 地址,IPv4 客户端访问报 Connection refused

# 查看监听地址
$ ss -tlnp | grep :80
LISTEN 0 511 [::]:80 *:* users:(("nginx",pid=1234,fd=6))
# [::]:80 表示只监听 IPv6

# 修复:在 nginx.conf 中添加 IPv4 监听
server {
    listen 80;           # 监听所有 IPv4 地址
    listen [::]:80;      # 监听所有 IPv6 地址
    ...
}

根因:某些发行版默认配置优先使用 IPv6,而客户端通过 IPv4 连接时无法匹配。Nginx 的 listen 指令决定了绑定的地址族,只配置 [::]:80 会忽略所有 IPv4 请求。

修复:在配置文件中同时添加 listen 80(IPv4)和 listen [::]:80(IPv6),或仅 listen 80 监听所有地址。修改后用 nginx -t 测试配置语法,sudo systemctl reload nginx 重载配置。

案例 E:DNS 缓存导致域名解析不更新

现象:域名 A 记录已修改为新 IP,但服务器仍解析到旧 IP。

# 查看本地 DNS 缓存
$ resolvectl statistics
# 或
$ systemd-resolve --statistics

# 清除 systemd-resolved 缓存
$ sudo resolvectl flush-caches

# 验证解析结果
$ dig +short example.com
1.2.3.4    ← 已更新

# 如果使用 nscd 缓存
$ sudo systemctl restart nscd

# 临时禁用 DNS 缓存(调试用)
$ sudo systemd-resolve --set-dns=8.8.8.8 --set-domain=~.

根因:systemd-resolved 或 nscd 缓存了旧的 DNS 记录,TTL(Time To Live)未过期前不会重新查询。本地 DNS 缓存与上游 DNS 记录不同步。

修复sudo resolvectl flush-caches 清除缓存。长期方案:降低 DNS 记录的 TTL 值(如 300 秒),便于快速切换。检查 /etc/resolv.conf 确认 DNS 服务器配置正确。

案例 F:iptables 规则顺序导致端口放行失效

现象:执行 iptables -A INPUT -p tcp --dport 80 -j ACCEPT 放行 80 端口,但外部仍然无法访问。

# 查看规则顺序
$ sudo iptables -L INPUT -n --line-numbers
num  target   prot opt source       destination
1    DROP     all  --  0.0.0.0/0    0.0.0.0/0    ← 先匹配 DROP
2    ACCEPT   tcp  --  0.0.0.0/0    0.0.0.0/0    tcp dpt:80

# iptables 按顺序匹配,第一条 DROP 就丢弃了所有流量

根因-A(Append)将规则追加到链末尾,但前面已存在 DROP all 规则,所有流量在到达 ACCEPT 之前就被丢弃。iptables 按顺序匹配规则,第一条匹配的规则决定流量命运。

修复:用 -I INPUT 1(Insert)将规则插入到链的第一条位置:sudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT。也可以先删除旧规则再添加:sudo iptables -D INPUT -p tcp --dport 80 -j ACCEPT。建议用 ufw/nftables 替代原生 iptables,语法更清晰且不易出错。生产环境防火墙规则变更前务必做好备份和测试。

案例 G:SSH 端口修改后旧连接残留导致端口冲突

现象:修改 SSH 端口从 22 改为 2222 后重启 sshd,报 Address already in use

# 查看端口占用
$ ss -tlnp | grep :22
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1234,fd=4))

# 原因:旧的 sshd 进程仍在监听 22 端口
# 新配置要求同时监听 22 和 2222,但旧进程持有 22 端口

# 解决:先停止旧服务,再启动新配置
$ sudo systemctl stop sshd
$ sudo systemctl start sshd

# 验证
$ ss -tlnp | grep sshd
LISTEN 0 128 0.0.0.0:2222 0.0.0.0:* users:(("sshd",pid=5678,fd=3))

根因systemctl restart 在某些情况下会先启动新进程再停止旧进程,导致短暂的端口冲突。修改端口时尤其容易出现此问题。

修复:先 stopstart,避免 restart 的竞争条件。修改 SSH 端口前确保新端口已放行防火墙,否则会把自己锁在外面。

案例 H:systemd-resolved 导致 DNS 解析异常

现象:Ubuntu 24.04 上 ping google.com 正常但 curl https://api.example.comCould not resolve host

# 检查 DNS 解析
$ dig api.example.com
# 无输出——解析失败

$ dig @8.8.8.8 api.example.com
;; ANSWER SECTION:
api.example.com. 300 IN A 1.2.3.4    ← 手动指定 DNS 可以解析

# 检查 systemd-resolved 状态
$ resolvectl status
Global
         Protocols: +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
  resolv.conf mode: stub

# 问题:systemd-resolved 的 stub 监听异常
$ sudo systemctl restart systemd-resolved

# 验证
$ dig api.example.com
;; ANSWER SECTION:
api.example.com. 300 IN A 1.2.3.4    ← 修复

根因:Ubuntu 默认使用 systemd-resolved 管理 DNS,/etc/resolv.conf 指向 127.0.0.53(stub 转发器)。systemd-resolved 异常时会导致部分域名解析失败。传统 resolv.conf 方式配置的 DNS 服务器在此场景下不生效。

修复sudo systemctl restart systemd-resolved 重启解析服务。长期方案检查 /etc/resolv.conf 是否正确指向 stub 监听地址,或手动配置 /etc/systemd/resolved.conf 中的上游 DNS 服务器。

案例 I:tcp_tw_recycle 导致高并发下连接被随机丢弃

现象:服务器在高并发场景下出现大量 SYN timeout,部分客户端连接失败,但服务器 CPU 和内存正常。

# 检查 TIME_WAIT 状态连接数
$ ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
  8500 TIME-WAIT
  1200 ESTAB
    50 LISTEN

# 检查 tcp_tw_recycle 设置
$ sysctl net.ipv4.tcp_tw_recycle
net.ipv4.tcp_tw_recycle = 1    ← 已开启(危险!)

# 关闭 tcp_tw_recycle
$ sudo sysctl -w net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_tw_recycle = 0

# 永久生效
$ echo "net.ipv4.tcp_tw_recycle=0" | sudo tee -a /etc/sysctl.conf

# 调优建议
$ sudo sysctl -w net.ipv4.tcp_tw_reuse=1    ← 复用 TIME_WAIT
$ sudo sysctl -w net.ipv4.tcp_max_tw_buckets=5000

根因tcp_tw_recycle 在 NAT 环境下会导致问题——同一 NAT 出口的不同客户端共享 IP,但时间戳不同,内核会随机丢弃连接。Linux 4.12+ 已移除此选项。

修复sysctl -w net.ipv4.tcp_tw_recycle=0 关闭。改用 tcp_tw_reuse=1 允许复用 TIME_WAIT 连接。高并发服务器调整 tcp_max_tw_buckets 控制 TIME_WAIT 数量上限。

延伸阅读

↑ 回到顶部