上一篇 下一篇 分享链接 返回 返回顶部

Linux进程连不上远端服务?用ss和lsof按PID检查连接状态

发布人:Minchunlin 发布时间:2026-10-04 11:36 阅读量:3

要判断 Linux 进程为什么连不上远端服务,先确认“发起连接的到底是不是目标进程”,再查看该 PID 对应的本地地址、远端地址和 TCP 状态。ss 适合快速查看内核当前连接及监听状态,lsof 可以从进程文件描述符角度确认网络套接字;两者结合,能够把问题初步分到应用绑定、主机防火墙、安全组、NAT或远端服务未响应等范围。

实际排查时,先按 PID 检查进程是否存在网络连接,再判断结果是 ESTAB、SYN-SENT、LISTEN 还是完全没有套接字。ESTAB 只能证明 TCP 三次握手已完成,不代表应用层请求一定成功;SYN-SENT 通常说明连接请求发出后没有完成握手,需要继续核对路由、防火墙、安全组、NAT和远端监听状态。

准备条件

以下命令适用于常见 Linux 发行版,依赖:

  • ss:通常由 iproute2 提供。
  • lsof:部分精简系统可能未预装。
  • ps、ip、getent:用于确认进程、路由和名称解析。
  • systemctl、journalctl:仅适用于使用 systemd 管理服务的系统。

先准备目标 PID、远端主机和端口。示例中使用 PID 1234、远端地址 10.20.30.40:5432,请替换为实际值。

PID=1234
REMOTE_HOST=db.example.internal
REMOTE_IP=10.20.30.40
REMOTE_PORT=5432

确认 PID 没有填错:

ps -o pid,ppid,user,etime,stat,cmd -p "$PID"

如果只知道服务名,可以先查找进程:

pgrep -af '应用名称或关键启动参数'

对于 systemd 服务,也可以查看主进程 PID:

systemctl show -p MainPID --value app.service

没有 root 权限时,ss -p 和 lsof 可能无法显示其他用户进程的 PID、程序名或文件描述符。出现信息不完整时,使用 sudo 重复执行,不要仅凭空白结果判断进程没有连接。

第一步:确认进程是否持有网络套接字

使用 ss 按 PID 查看 TCP 连接

sudo ss -Hntp | grep -F "pid=$PID,"

参数含义:

  • -H:不显示表头,便于脚本处理。
  • -n:直接显示 IP 和端口,不进行反向解析。
  • -t:只看 TCP。
  • -p:显示关联的进程、PID和文件描述符。

典型输出可能类似:

ESTAB 0 0 192.168.1.20:41876 10.20.30.40:5432 users:(("app",pid=1234,fd=17))

这表示 PID 1234 的进程通过本地 192.168.1.20:41876 连接到 10.20.30.40:5432,当前 TCP 状态为 ESTAB。

查看该进程的 UDP 套接字:

sudo ss -Hnup | grep -F "pid=$PID,"

UDP 没有 TCP 那样完整的握手状态。输出中的 UNCONN 不等于网络一定不可达,只能说明该套接字没有处于 TCP 式连接状态。对于 UDP,需要结合应用日志、抓包或远端服务响应判断。

使用 lsof 从文件描述符确认连接

sudo lsof -nP -a -p "$PID" -i

分别查看 TCP 和 UDP:

sudo lsof -nP -a -p "$PID" -iTCP
sudo lsof -nP -a -p "$PID" -iUDP

典型 TCP 输出:

COMMAND PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
app    1234 app    17u  IPv4  98765      0t0  TCP 192.168.1.20:41876->10.20.30.40:5432 (ESTABLISHED)

重点核对以下字段:

  • PID:是否为目标进程。
  • FD:套接字对应的文件描述符。
  • TYPE:是 IPv4 还是 IPv6。
  • NAME:本地地址、远端地址和连接状态。
  • 远端端口:是否确实是业务要求的端口,而不是配置中的旧端口。

ss 反映内核当前网络状态,刷新速度快;lsof反映进程打开的文件描述符。若两者结果不一致,先考虑连接变化、权限不足、网络命名空间不同或进程刚好关闭了短连接。

第一步:确认进程是否持有网络套接字配图

第二步:区分 TCP 状态,确定故障边界

可以用下面的命令持续观察一个短时间窗口,避免短连接刚建立就消失:

for i in $(seq 1 10); do
    date -Is
    sudo ss -Hntp | grep -F "pid=$PID," || true
    sleep 1
done

常见状态与判断方式如下:

观察结果正常与异常分界优先检查方向
ESTABTCP 握手已完成,网络层连接基本建立应用协议、认证、TLS、请求超时和远端服务日志
SYN-SENT本机发出 SYN,但暂未收到 SYN-ACK路由、主机出站策略、安全组出站、NAT、远端入口和远端监听
SYN-RECV本机收到连接请求,但握手未完成本机回包路径、防火墙状态规则、对端回包和中间设备
TIME-WAIT本地连接已关闭后的正常保留状态通常不是当前连不上;连接创建过于频繁时再检查端口和资源
CLOSE-WAIT对端已关闭,本地进程尚未关闭套接字应用没有及时释放连接,重点看应用代码或连接池
没有任何记录当前没有被观测到的网络套接字PID、配置、DNS、短连接时机、网络命名空间和权限
UDP UNCONNUDP 套接字存在,但没有 TCP 式连接状态应用发送逻辑、返回包、服务端口和抓包结果

SYN-SENT 是端口连接排查中的重要分界点。它说明应用至少创建了 TCP 连接并尝试发起请求,但不能单凭这一行确定是本机防火墙、云安全组、NAT还是远端服务拒绝。需要继续执行后续检查。

如果显示 ESTAB,但应用仍报“连接失败”,网络握手已经成功,故障通常发生在握手之后,例如远端协议不匹配、认证失败、TLS协商失败、连接池配置错误或应用等待响应超时。此时不要反复修改端口放行规则。

第三步:检查本机是否正确监听和绑定

如果故障是“其他机器连不上本机服务”,先查看监听状态:

sudo ss -lntp

按端口筛选:

sudo ss -lntp 'sport = :8080'

使用 lsof 交叉确认:

sudo lsof -nP -iTCP:8080 -sTCP:LISTEN

也可以按 PID 查看监听套接字:

sudo ss -Hlnpt | grep -F "pid=$PID,"
sudo lsof -nP -a -p "$PID" -iTCP -sTCP:LISTEN

重点区分以下绑定结果:

  • 127.0.0.1:8080:只接受本机回环接口连接,远程机器无法直接访问。
  • 192.168.1.20:8080:只绑定指定网卡地址,访问其他网卡地址或公网映射地址可能失败。
  • 0.0.0.0:8080:监听所有 IPv4 网卡,但仍可能被本机防火墙、安全组或NAT阻断。
  • [::]:8080:监听 IPv6;是否同时接受 IPv4 取决于系统的 IPv6 双栈设置。
  • 没有监听记录:应用可能没有启动成功、实际使用了其他端口、绑定失败,或者监听套接字位于其他网络命名空间。

检查本机地址和路由:

ip -br addr
ip route

如果应用绑定了一个已经不存在的地址,常见表现是启动时报 Cannot assign requested address,或者服务启动后没有对应监听端口。此时查看启动参数和服务配置:

tr '\0' ' ' < /proc/"$PID"/cmdline
echo

如果由 systemd 管理:

systemctl cat app.service
systemctl status app.service --no-pager
journalctl -u app.service -n 100 --no-pager

不要因为看到 0.0.0.0:8080 就认为公网访问一定正常。它只说明应用在本机 IPv4 地址上监听,不能证明云安全组、入口NAT或外部防火墙已经放行。

第四步:核对远端地址、解析和路由

先确认应用使用的域名解析到了哪个地址:

getent ahosts "$REMOTE_HOST"

如果应用配置使用域名,而 ss 中显示的远端 IP 与预期不一致,应继续核对:

  • DNS是否解析到了正确地址。
  • 应用是否缓存了旧解析结果。
  • IPv4和IPv6是否选择了不同路径。
  • 远端端口是否与配置一致。

查看到目标 IP 的路由和源地址选择:

ip route get "$REMOTE_IP"

示例结果可能包含:

10.20.30.40 via 192.168.1.1 dev eth0 src 192.168.1.20

这表示系统计划通过 eth0、网关 192.168.1.1,使用源地址 192.168.1.20 访问远端。若路由不存在、接口状态异常,或者源地址不是安全组允许的地址,连接可能停留在 SYN-SENT。

在不影响应用配置的前提下,可以从同一台主机、同一网络命名空间进行 TCP 探测:

nc -vz -w 3 "$REMOTE_IP" "$REMOTE_PORT"

该命令仅用于验证主机到目标端口的基础 TCP连通性,不能证明目标进程使用的配置、认证和应用协议正常。如果系统没有 nc,不要把“命令不存在”误判成端口不通,应使用已有探测工具或直接结合 ss、应用日志和抓包判断。

第五步:检查主机防火墙

主机防火墙需要分别考虑入站和出站方向。访问远端服务时,即使本机没有入站监听,也可能存在出站限制;提供本机服务时,则重点检查入站规则。

优先确认系统实际使用哪套防火墙管理工具,只查看,不要同时修改多套规则:

sudo firewall-cmd --state 2>/dev/null
sudo firewall-cmd --list-all 2>/dev/null

如果使用 UFW:

sudo ufw status verbose

如果使用 nftables:

sudo nft list ruleset

如果系统仍使用 iptables 规则:

sudo iptables -S
sudo iptables -L -n -v

检查时重点看:

  • 目标端口和协议是否匹配,例如 TCP 5432 与 UDP 5432 不是同一条规则。
  • 规则匹配的接口是否正确,例如只允许 eth0,但流量实际从其他接口进入。
  • 源地址或目标地址是否写错。
  • 默认策略是否为 DROP 或 REJECT。
  • 出站方向是否限制了远端端口或临时源端口。
  • 是否存在按连接状态放行返回包的规则。

DROP通常表现为连接长时间停留在 SYN-SENT或探测超时;REJECT可能较快返回错误,但具体表现还取决于规则和协议。仅凭客户端超时不能直接确认是防火墙丢包。

不要使用 iptables -F、nft flush ruleset 等清空规则的方式“快速测试”,这可能导致远程登录中断、业务端口暴露或整台主机失去访问控制。如果必须临时调整规则,先保存当前规则和管理工具配置,限定源地址、目标端口及测试时间,并记录变更前后的规则;验证完成后删除临时规则或按原配置恢复。

第六步:核对安全组、NAT和入口映射

主机上的 ss 和 lsof 看不到云平台安全组的最终判定,也看不到NAT设备转换后的完整连接。需要按照流量方向核对。

访问远端服务时

流量通常类似:

进程本地地址:临时端口
        ↓
本机路由和出站防火墙
        ↓
出口NAT或网关
        ↓
远端安全组入站规则
        ↓
远端主机监听端口

重点确认:

  • 本机安全组是否允许出站到远端 IP 和目标端口。
  • 出口NAT是否存在、是否有可用地址和端口资源。
  • 远端安全组入站规则是否允许本机实际的出口公网 IP 或网段。
  • 远端服务是否监听在正确的私网或公网地址。
  • 中间网络设备是否只允许特定源端口、目的端口或协议。

需要注意,ss 显示的是本机NAT之前的本地地址和临时端口,不能直接证明远端看到的源公网 IP。远端日志、云流日志或出口网关记录更适合确认NAT后的源地址。

外部访问本机服务时

流量通常类似:

客户端
  ↓
公网地址:公网端口
  ↓
入口NAT或负载均衡
  ↓
云安全组和网络访问控制
  ↓
私网地址:目标端口
  ↓
应用监听套接字

应逐项核对:

  1. 公网端口是否映射到正确的私网 IP 和端口。
  2. 映射协议是否为 TCP,是否误配成 UDP。
  3. 安全组入站规则的源地址范围是否包含客户端。
  4. 入口映射后的目标端口是否与 ss -lntp 中的监听端口一致。
  5. 应用是否只绑定了 127.0.0.1。
  6. 主机防火墙是否允许映射后的入站流量。

如果主机完全看不到来自客户端的连接尝试,优先检查NAT、安全组、网络访问控制和入口地址;如果主机能看到 SYN,但没有形成连接,再检查本机监听状态、防火墙和回包路径。

第七步:用抓包确认数据包走到哪一步

当 ss 长时间显示 SYN-SENT,或者安全组和防火墙规则看起来都正常,可以在限定时间内抓取目标流量。抓包可能包含业务数据和敏感地址,应限制目标、时间和文件权限。

OUT=/tmp/port-check-$(date +%Y%m%d-%H%M%S)
mkdir -m 700 "$OUT"

sudo timeout 30 tcpdump -ni any \
  "host $REMOTE_IP and tcp port $REMOTE_PORT" \
  -c 50 -w "$OUT/flow.pcap"

如果只需要在终端观察握手,不保存数据包:

sudo timeout 30 tcpdump -ni any \
  "host $REMOTE_IP and tcp port $REMOTE_PORT" \
  -c 20

常见判断方式:

  • 能看到本机发出的 SYN,看不到 SYN-ACK:远端未响应,或中间设备丢弃返回包。
  • 能看到 SYN 和 RST:某一端主动拒绝,常见于端口未监听或策略拒绝。
  • 能看到完整握手,但应用仍报错:网络连接已经建立,应转向应用协议和日志。
  • 完全看不到本机发出的 SYN:进程可能没有真正发起连接、连接尝试尚未发生、目标地址解析错误,或抓包接口和网络命名空间不对。

抓包只用于定位,不要把保存的 .pcap 文件直接上传到公开位置。完成取证后,按组织的敏感信息保留周期处理。

常见失败处理

ss 没有显示 PID 或程序名

先用 root 权限执行:

sudo ss -ntup
sudo lsof -nP -a -p "$PID" -i

如果仍然没有结果,检查 PID 是否属于容器或其他网络命名空间。目标进程存在但主机网络视图中看不到时,可在确认权限和容器管理方式后进入该进程的网络命名空间:

sudo nsenter -t "$PID" -n ss -Hntup

nsenter 只查看网络状态,不会修改配置;但进入错误 PID 可能看到不相关的网络空间,执行前应先用 ps确认目标进程。

没有连接记录,但应用日志显示连接失败

可能原因包括:

  • 应用尚未执行到真正的连接代码。
  • 连接是短暂创建后立即关闭。
  • 应用使用 UDP,检查时只查看了 TCP。
  • 应用在另一个容器或网络命名空间中。
  • 使用了错误的 PID,例如查看了父进程而不是工作进程。
  • DNS解析或配置校验在创建套接字前就已经失败。

应同时采集应用日志、重复执行 ss,并确认启动参数和配置中的远端地址。

只有 SYN-SENT

先按以下顺序处理:

常见失败处理:只有 SYN-SENT配图

  1. 用 getent ahosts确认域名解析。
  2. 用 ip route get确认路由和源地址。
  3. 查看本机出站防火墙。
  4. 查看云安全组出站和远端安全组入站。
  5. 核对出口NAT和远端监听。
  6. 必要时短时抓包确认是否有 SYN-ACK返回。

不要在没有证据时直接重启应用或修改远端服务端口。重启通常只能清除现有连接,无法修复路由、安全组或NAT问题。

显示 ESTAB,但程序仍然报错

此时 TCP 连接已经建立。重点收集:

sudo lsof -nP -a -p "$PID" -iTCP
sudo ss -Hntpo | grep -F "pid=$PID,"

关注发送队列、接收队列、连接持续时间和应用日志。若握手完成后长时间没有响应,可能是远端应用处理慢、协议不匹配、认证失败或连接池复用异常,而不是端口未开放。

本机有监听,远程仍然连接不上

检查监听地址是否为回环地址,再依次核对:

  • 本机防火墙入站策略。
  • 云安全组入站规则。
  • NAT或负载均衡的目标端口。
  • 网络访问控制列表。
  • 客户端访问的 IP 是否与实际映射地址一致。

如果本机抓包能看到客户端 SYN,但应用没有回复,优先看监听端口、绑定地址和主机防火墙;如果完全看不到 SYN,优先看安全组、NAT和入口路径。

留证与结果验收

排查结束前,建议在受限目录中保存一次完整现场。下面的命令只读取状态,不修改网络配置:

OUT=/tmp/port-check-$(date +%Y%m%d-%H%M%S)
mkdir -m 700 "$OUT"

{
    echo "=== time ==="
    date -Is
    echo "=== host ==="
    hostname
    echo "=== process ==="
    ps -o pid,ppid,user,etime,stat,cmd -p "$PID"
    echo "=== cmdline ==="
    tr '\0' ' ' < /proc/"$PID"/cmdline
    echo
    echo "=== ss by pid ==="
    sudo ss -Hntup | grep -F "pid=$PID," || true
    echo "=== listening ==="
    sudo ss -Hlnpt
    echo "=== lsof by pid ==="
    sudo lsof -nP -a -p "$PID" -i
    echo "=== address ==="
    ip -br addr
    echo "=== route ==="
    ip route get "$REMOTE_IP"
} 2>&1 | tee "$OUT/summary.txt"

验收时至少应得到以下明确结论:

  • 目标 PID 与实际业务进程一致。
  • ss 和 lsof 能看到目标进程的网络套接字,或已经说明为什么没有套接字。
  • 远端 IP和端口与配置一致。
  • 访问远端服务时,连接状态达到 ESTAB,或者已根据 SYN-SENT定位到具体网络边界。
  • 提供本机服务时,监听端口、协议和绑定地址符合要求。
  • 本机防火墙的入站或出站策略与访问方向一致。
  • 安全组规则的方向、源地址、目标端口和关联实例正确。
  • NAT或端口映射的前后端地址和端口一致。
  • 通过重复观察或抓包确认结果,而不是只依据一次瞬时输出。
  • 记录命令执行时间、主机名、PID、监听地址、远端地址和异常状态,并对公网 IP、命令行中的密码或业务数据进行脱敏。

修改后的回滚要求

端口排查应优先采用只读命令。确需修改应用绑定、防火墙或安全组时,先保存当前配置和验收现场,再进行单项变更。

  • 修改应用监听地址或端口前,备份配置文件,确认变更影响的服务和监听端口;优先使用应用支持的 reload,若必须 restart,要预留业务中断窗口。
  • 修改主机防火墙前,导出当前规则,保留远程登录所需的管理端口;不要清空全部规则。
  • 添加临时放行规则时,限制源地址、目标端口和有效时间,并记录规则编号或 nftables 句柄。
  • 验证失败时,先删除临时规则或恢复变更前的配置,再重新执行 ss、lsof和连通性检查。
  • 只有确认新监听已正常工作、旧端口不再使用且回滚路径可用后,才清理旧配置。

上线或验收检查清单

  • [ ] 已确认正确的服务 PID、用户和启动参数。
  • [ ] 已用 ss 按 PID 查看 TCP/UDP套接字。
  • [ ] 已用 lsof确认网络文件描述符、协议和远端端点。
  • [ ] 已记录连接状态:ESTAB、SYN-SENT、LISTEN或其他状态。
  • [ ] 已确认远端域名解析结果、目标 IP和目标端口。
  • [ ] 已用 ip route get核对出口接口和源地址。
  • [ ] 已确认服务监听地址不是错误的 127.0.0.1或失效地址。
  • [ ] 已检查本机防火墙对应方向的规则和默认策略。
  • [ ] 已检查云安全组入站或出站规则。
  • [ ] 已核对NAT、端口映射或负载均衡前后端端口。
  • [ ] 必要时已通过抓包确认 SYN、SYN-ACK和应用数据的实际路径。
  • [ ] 已保存带时间戳的命令输出和日志,并完成敏感信息脱敏。
  • [ ] 如做过规则或配置调整,已验证回滚方法可执行。
目录结构
全文