网络基础

22 分钟阅读 · 33 组命令示例

端口管理完全指南:PowerShell / Linux Bash / Git Bash

适用场景:开发时查端口占用、杀僵尸进程、调试服务连接、配置防火墙规则。

适用版本:Windows 10/11、PowerShell 7+、现代 Linux(iproute2)、Git Bash。

最后核对:2026-07-30

30 秒快速路径

powershell
Get-NetTCPConnection -LocalPort 4321 -State Listen
Get-Process -Id (Get-NetTCPConnection -LocalPort 4321 -State Listen).OwningProcess
Test-NetConnection localhost -Port 4321

目录

  1. 核心概念
  2. PowerShell (Windows 原生)
  3. Linux Bash / WSL
  4. Git Bash (MINGW64)
  5. 三平台速查对照表
  6. 进阶用法
  7. 常见问题排查
  8. 推荐的个人习惯

核心概念

端口是什么

端口是传输层协议用来区分网络通信端点的数字编号(0-65535)。通常情况下,同一协议、同一本地地址和同一端口组成的监听端点只能被一个 socket 占用;SO_REUSEPORT、父子进程共享 socket、不同本地地址或 IPv4/IPv6 分别监听等情况例外。

关键术语

术语 含义
LISTEN 进程正在监听该端口,等待连接
ESTABLISHED 已有活跃连接
TIME_WAIT 主动关闭方暂时保留已关闭连接的状态,防止延迟报文影响新连接;不等于整个端口被锁定
PID Process ID,进程唯一标识符
0.0.0.0 监听所有网卡接口
127.0.0.1 仅监听本机回环(localhost)
::1 IPv6 的 localhost

常用端口号

端口 服务
80 HTTP
443 HTTPS
3000 React/Next.js 开发服务器
4321 Astro 开发服务器
5173 Vite 开发服务器
8080 常见代理/开发端口
3306 MySQL
5432 PostgreSQL
6379 Redis

思维模型

所有端口操作的核心链路:

text
端口号 → PID(进程ID)→ 进程名/命令行

反向也成立:

text
进程名 → PID → 它占了哪些端口

PowerShell (Windows 原生)

查看端口占用

powershell
# ═══ 基础查询 ═══

# 查看所有正在监听的 TCP 端口
Get-NetTCPConnection -State Listen

# 查看特定端口的监听者
Get-NetTCPConnection -LocalPort 4321 -State Listen

# 查看特定端口 + 进程名(最实用的一行)
Get-NetTCPConnection -LocalPort 4321 -State Listen | 
  Select-Object LocalPort, OwningProcess, 
    @{N='Process'; E={(Get-Process -Id $_.OwningProcess).ProcessName}}


# ═══ 格式化输出 ═══

# 所有监听端口,按端口号排序,表格显示
Get-NetTCPConnection -State Listen | 
  Select-Object LocalPort, OwningProcess, 
    @{N='Name'; E={(Get-Process -Id $_.OwningProcess).ProcessName}} | 
  Sort-Object LocalPort | 
  Format-Table -AutoSize

# 只看 node 进程占了哪些端口
Get-NetTCPConnection -State Listen | 
  Where-Object { (Get-Process -Id $_.OwningProcess).ProcessName -eq 'node' }


# ═══ UDP 端口(较少用)═══

Get-NetUDPEndpoint | Select-Object LocalPort, OwningProcess

杀掉占端口的进程

powershell
# 只选择监听该端口的进程,并去重
$listenerPids = Get-NetTCPConnection -LocalPort 4321 -State Listen -ErrorAction SilentlyContinue |
  Select-Object -ExpandProperty OwningProcess -Unique

if ($listenerPids) {
  # 先确认进程。优先在原终端按 Ctrl+C,让服务自行清理退出
  Get-Process -Id $listenerPids

  # 确认后终止
  $listenerPids | ForEach-Object { Stop-Process -Id $_ }

  # 只有普通终止失败且确认目标无误时,才以管理员身份强制终止
  # $listenerPids | ForEach-Object { Stop-Process -Id $_ -Force }
} else {
  Write-Host "TCP 4321 当前没有监听者"
}

通过 PID 查进程详情

powershell
# 基本信息
Get-Process -Id 18992

# 查看完整命令行(能看到进程跑的是什么脚本/文件)
Get-CimInstance Win32_Process -Filter "ProcessId=18992" | 
  Select-Object ProcessId, Name, CommandLine

# 查看进程的父进程(谁启动了它)
Get-CimInstance Win32_Process -Filter "ProcessId=18992" | 
  Select-Object ProcessId, ParentProcessId, Name

测试端口连通性

powershell
# 完整测试(输出详细信息)
Test-NetConnection -ComputerName localhost -Port 4321

# 只看结果 True/False
(Test-NetConnection localhost -Port 4321).TcpTestSucceeded

# 测试远程主机
Test-NetConnection -ComputerName google.com -Port 443

# 批量测试多个端口
@(80, 443, 3000, 4321, 8080) | ForEach-Object {
  [PSCustomObject]@{
    Port = $_
    Open = (Test-NetConnection localhost -Port $_ -WarningAction SilentlyContinue).TcpTestSucceeded
  }
} | Format-Table

netstat 传统用法(PowerShell 里也能跑)

powershell
# 所有监听端口
netstat -ano | findstr LISTENING

# 特定端口
netstat -ano | findstr :4321

# 输出格式解读:
# 协议   本地地址          远程地址        状态       PID
# TCP    0.0.0.0:4321     0.0.0.0:0      LISTENING  18992

防火墙管理(需要管理员权限)

powershell
# 查看所有启用的入站规则
Get-NetFirewallRule -Direction Inbound -Enabled True | 
  Get-NetFirewallPortFilter | 
  Where-Object LocalPort -ne $null |
  Select-Object @{N='Rule';E={(Get-NetFirewallRule -AssociatedNetFirewallPortFilter $_).DisplayName}}, 
    LocalPort, Protocol |
  Sort-Object LocalPort

# 查看允许 TCP 4321 入站的已启用规则
Get-NetFirewallRule -Direction Inbound -Enabled True -Action Allow |
  Where-Object {
    $portFilter = $_ | Get-NetFirewallPortFilter
    $portFilter.Protocol -eq 'TCP' -and $portFilter.LocalPort -contains '4321'
  } |
  Select-Object DisplayName, Enabled, Direction, Action, Profile

# 开放端口
New-NetFirewallRule -DisplayName "Allow Port 4321" `
  -Direction Inbound -LocalPort 4321 -Protocol TCP -Action Allow

# 删除规则
Remove-NetFirewallRule -DisplayName "Allow Port 4321"

# 临时禁用规则(不删除)
Disable-NetFirewallRule -DisplayName "Allow Port 4321"

Linux Bash / WSL

查看端口占用

bash
# ═══ ss 命令(推荐,速度快)═══

# 所有监听的 TCP 端口
ss -tlnp
# 参数含义:t=TCP  l=Listen  n=数字显示(不解析域名)  p=显示进程

# 查特定 TCP 监听端口(避免 grep 把 14321 也匹配进来)
ss -ltnp 'sport = :4321'
# 输出示例:LISTEN  0  511  *:4321  *:*  users:(("node",pid=1234,fd=18))

# 包含 UDP
ss -tulnp


# ═══ lsof 命令(更直观)═══

# 查特定 TCP 监听端口(查看其他用户的进程通常需要 sudo)
sudo lsof -nP -iTCP:4321 -sTCP:LISTEN
# 输出示例:
# COMMAND  PID  USER  FD  TYPE  DEVICE  SIZE/OFF  NODE  NAME
# node    1234  user  18u  IPv4  12345  0t0       TCP   *:4321 (LISTEN)

# 只输出监听者 PID(方便管道给 kill)
sudo lsof -t -iTCP:4321 -sTCP:LISTEN

# 查某个进程打开的所有网络连接
lsof -i -a -p 1234


# ═══ netstat(老工具,有些系统已移除)═══

netstat -tlnp
# 如果提示 command not found,装一下:apt install net-tools


# ═══ fuser(另一种方式)═══

# 查谁占了端口
fuser 4321/tcp
# 输出:4321/tcp:  1234

# 直接杀会影响所有匹配该端口的进程,先确认输出再使用
fuser -k 4321/tcp

杀掉占端口的进程

bash
# 标准做法:只查 TCP 监听者,确认后再终止
sudo lsof -nP -iTCP:4321 -sTCP:LISTEN
listener_pids=$(sudo lsof -t -iTCP:4321 -sTCP:LISTEN)
[ -n "$listener_pids" ] && ps -fp $listener_pids
[ -n "$listener_pids" ] && kill $listener_pids       # SIGTERM

# 只有进程拒绝正常退出时才使用 SIGKILL
[ -n "$listener_pids" ] && kill -9 $listener_pids

# 知道 PID 直接杀
kill 1234                        # SIGTERM(进程可以优雅退出)
kill -9 1234                     # SIGKILL(立即终止,不给机会清理)
kill -15 1234                    # 同 kill,SIGTERM 的数字形式

# 按进程名杀(杀所有同名进程)
killall node                     # 杀所有 node 进程
pkill -f "astro dev"            # 按命令行模式匹配杀

信号(Signal)说明

bash
# Linux 的 kill 不是"杀",是"发信号"
kill -l                          # 列出所有信号

# 常用信号:
# SIGTERM (15) - 温和终止,进程可以捕获并优雅退出
# SIGKILL (9)  - 强制终止,进程无法捕获,立即死
# SIGHUP  (1)  - 挂起,有些服务用来重新加载配置
# SIGINT  (2)  - 中断,等同于 Ctrl+C

通过 PID 查进程详情

bash
# 查看进程基本信息
ps -p 1234 -o pid,ppid,user,comm,args

# 查看完整命令行
cat /proc/1234/cmdline | tr '\0' ' '

# 查看进程的环境变量(可能包含密码、Token 等敏感信息,不要粘贴到日志或聊天)
cat /proc/1234/environ | tr '\0' '\n'

# 查看进程的工作目录
ls -l /proc/1234/cwd

# 查看进程树(谁启动了谁)
pstree -p 1234

测试端口连通性

bash
# nc (netcat) — 最通用
nc -zv localhost 4321
# -z 扫描模式(不发数据)  -v 详细输出
# 成功:Connection to localhost 4321 port [tcp/*] succeeded!
# 失败:nc: connect to localhost port 4321 (tcp) failed: Connection refused

# 用 curl 测试 HTTP 服务
curl -s -o /dev/null -w "%{http_code}" http://localhost:4321
# 任何 HTTP 状态码都表示 HTTP 服务作出了响应;是否健康要按应用约定判断

# 用 bash 内置(不依赖外部工具)
(echo > /dev/tcp/localhost/4321) 2>/dev/null && echo "开放" || echo "关闭"

# 批量扫描端口
for port in 80 443 3000 4321 8080; do
  (echo > /dev/tcp/localhost/$port) 2>/dev/null && echo "$port: 开放" || echo "$port: 关闭"
done

防火墙管理

bash
# ═══ ufw(Ubuntu 简化防火墙)═══
sudo ufw status                  # 查看状态
sudo ufw allow 4321/tcp         # 开放端口
sudo ufw deny 4321/tcp          # 拒绝端口
sudo ufw delete allow 4321/tcp  # 删除规则

# ═══ iptables(部分系统使用;现代发行版可能采用 nftables 或兼容层)═══
# 注意规则顺序和持久化方式因发行版而异
sudo iptables -L -n             # 列出所有规则
sudo iptables -A INPUT -p tcp --dport 4321 -j ACCEPT   # 开放
sudo iptables -A INPUT -p tcp --dport 4321 -j DROP     # 拒绝
sudo iptables -D INPUT -p tcp --dport 4321 -j ACCEPT   # 删除

# ═══ firewalld(CentOS/Fedora)═══
sudo firewall-cmd --list-ports
sudo firewall-cmd --add-port=4321/tcp --permanent
sudo firewall-cmd --reload

Git Bash (MINGW64)

Git Bash 提供 Bash 和部分 Unix 工具,但通常没有 Linux 的 sslsofkill 是 Bash 内建命令,主要适用于 MSYS 进程;管理任意 Windows 原生进程时通常仍使用 netstattasklisttaskkill

查看端口占用

bash
# 查特定 TCP 监听端口(精确匹配本地端口)
netstat -ano | awk '$1 == "TCP" && $2 ~ /:4321$/ && $4 == "LISTENING"'
# 输出: TCP  0.0.0.0:4321  0.0.0.0:0  LISTENING  18992

# 所有监听端口
netstat -ano | grep LISTEN

# 提取并去重 PID
netstat -ano | awk '$1 == "TCP" && $2 ~ /:4321$/ && $4 == "LISTENING" {print $5}' | sort -u
# 输出: 18992

杀掉占端口的进程

bash
# 知道 PID 后先确认,再终止(注意双斜杠)
tasklist //FI "PID eq 18992"
taskkill //PID 18992

# 只有普通终止失败且目标无误时才强制终止
taskkill //F //PID 18992

# 按进程名杀
taskkill //F //IM node.exe

# 组合:精确查到监听者 PID,先显示,确认后再逐个终止
target_pids=$(netstat -ano | awk '$1 == "TCP" && $2 ~ /:4321$/ && $4 == "LISTENING" {print $5}' | sort -u)
for target_pid in $target_pids; do tasklist //FI "PID eq $target_pid"; done
for target_pid in $target_pids; do taskkill //PID "$target_pid"; done

查进程信息

bash
# 查所有进程
tasklist

# 过滤进程名
tasklist | grep node

# 过滤 PID
tasklist | grep 18992

测试端口

bash
# curl 测试(Git Bash 自带 curl)
curl -s -o /dev/null -w "%{http_code}" http://localhost:4321

# 查看完整 HTTP 交互;HTTP 错误状态也说明服务作出了响应
curl -v http://localhost:4321

Git Bash 的坑

bash
# 1. 参数前缀用 // 而不是 /
taskkill //F //PID 1234      # 正确
taskkill /F /PID 1234        # 错误!Git Bash 会把 / 当路径

# 2. 通常没有 Linux 的 ss、lsof
# kill 是 Bash 内建命令,但不能当作管理所有 Windows 原生进程的通用工具

# 3. 路径分隔符混乱
# Windows 路径:C:\Users\yourname
# Git Bash 路径:/c/Users/yourname
# Windows 原生程序通常接受 Windows 路径,Unix 工具通常使用 /c/...;
# MSYS 的自动路径转换并非对所有参数都可靠

三平台速查对照表

日常操作

操作 PowerShell Linux Bash Git Bash
所有监听端口 Get-NetTCPConnection -State Listen ss -tlnp netstat -ano | grep LISTEN
查谁监听 4321 Get-NetTCPConnection -LocalPort 4321 -State Listen sudo lsof -nP -iTCP:4321 -sTCP:LISTEN netstat -ano | awk '$1=="TCP" && $2~/:4321$/ && $4=="LISTENING"'
只拿 PID (... | Select-Object -ExpandProperty OwningProcess -Unique) sudo lsof -t -iTCP:4321 -sTCP:LISTEN 上一条命令后加 {print $5}sort -u
终止已确认的 PID Stop-Process -Id 18992 kill 1234 taskkill //PID 18992
强制终止(最后手段) Stop-Process -Id 18992 -Force kill -9 1234 taskkill //F //PID 18992
测试 TCP 端口 Test-NetConnection localhost -Port 4321 nc -zv localhost 4321 powershell.exe -NoProfile -Command "Test-NetConnection localhost -Port 4321"
PID → 进程名 (Get-Process -Id 18992).ProcessName ps -p 1234 -o comm= tasklist //FI "PID eq 18992"
按名字杀进程 Stop-Process -Name node killall node taskkill //IM node.exe

进阶操作

操作 PowerShell Linux Bash Git Bash
查进程命令行 Get-CimInstance Win32_Process -Filter "ProcessId=18992" | Select CommandLine cat /proc/1234/cmdline | tr '\0' ' ' powershell.exe -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'ProcessId=18992' | Select-Object -ExpandProperty CommandLine"
某程序占的所有端口 Get-NetTCPConnection -OwningProcess (Get-Process -Name node).Id ss -tlnp | grep node netstat -ano | grep $(tasklist | grep node | awk '{print $2}')
开放防火墙端口 New-NetFirewallRule ... sudo ufw allow 4321/tcp N/A (用 PowerShell)
批量测端口 ForEach-Object 循环 for 循环 + /dev/tcp for 循环 + curl

进阶用法

监控端口变化(实时观察)

powershell
# PowerShell:每 2 秒刷新一次监听端口列表
while ($true) { 
  Clear-Host
  Get-NetTCPConnection -State Listen | 
    Select LocalPort, OwningProcess, @{N='Name';E={(Get-Process -Id $_.OwningProcess).Name}} | 
    Sort LocalPort | Format-Table -AutoSize
  Start-Sleep 2 
}
bash
# Linux:用 watch 命令
watch -n 2 'ss -tlnp'

# 或者持续监控某个端口是否出现
while true; do ss -ltn 'sport = :4321' | grep -q LISTEN && echo "UP" || echo "DOWN"; sleep 1; done

等待端口就绪(脚本里常用)

powershell
# PowerShell:等待服务启动
function Wait-Port {
  param([int]$Port, [int]$Timeout = 30)
  $start = Get-Date
  while (((Get-Date) - $start).TotalSeconds -lt $Timeout) {
    if ((Test-NetConnection localhost -Port $Port -WarningAction SilentlyContinue).TcpTestSucceeded) {
      Write-Host "端口 $Port 已就绪"
      return $true
    }
    Start-Sleep 1
  }
  Write-Host "超时:端口 $Port 未就绪"
  return $false
}

Wait-Port -Port 4321 -Timeout 15
bash
# Linux:等待端口就绪
wait_port() {
  local port=$1 timeout=${2:-30} elapsed=0
  while [ $elapsed -lt $timeout ]; do
    (echo > /dev/tcp/localhost/$port) 2>/dev/null && echo "端口 $port 已就绪" && return 0
    sleep 1
    elapsed=$((elapsed + 1))
  done
  echo "超时:端口 $port 未就绪" && return 1
}

wait_port 4321 15

查看端口对应的完整连接信息

powershell
# PowerShell:查看某端口的所有连接状态
Get-NetTCPConnection -LocalPort 4321 | 
  Select-Object State, LocalAddress, LocalPort, RemoteAddress, RemotePort, OwningProcess |
  Format-Table -AutoSize
bash
# Linux:查看连接详情
ss -tnp sport = :4321
# 输出所有与 4321 端口相关的连接(包括 LISTEN 和 ESTABLISHED)

端口转发(开发调试用)

powershell
# PowerShell:只在本机回环地址上将 8080 转发到 4321(需要管理员)
netsh interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=8080 connectaddress=127.0.0.1 connectport=4321

# 查看已有的转发规则
netsh interface portproxy show all

# 删除转发
netsh interface portproxy delete v4tov4 listenaddress=127.0.0.1 listenport=8080
bash
# Linux:只绑定回环地址,避免意外暴露到局域网
socat TCP-LISTEN:8080,bind=127.0.0.1,reuseaddr,fork TCP:127.0.0.1:4321

# 或者把本机 8080 安全转发到远程主机上的 4321
ssh -L 127.0.0.1:8080:127.0.0.1:4321 user@remote-host

常见问题排查

"端口已被占用" (EADDRINUSE)

powershell
# 1. 查出是谁
Get-NetTCPConnection -LocalPort 4321 -State Listen | 
  Select LocalPort, OwningProcess, @{N='Name';E={(Get-Process -Id $_.OwningProcess).Name}}

# 2. 判断要不要杀
#    - 如果是自己之前没关干净的 node 进程 → 杀
#    - 如果是系统服务 → 换个端口

# 3. 杀掉后重新启动
$listenerPids = Get-NetTCPConnection -LocalPort 4321 -State Listen |
  Select-Object -ExpandProperty OwningProcess -Unique
$listenerPids | ForEach-Object { Stop-Process -Id $_ }
npm run dev

"Connection refused"

目标地址和端口没有接受连接。可能的原因:

  • 服务没启动
  • 服务崩了
  • 服务监听在不同地址(比如 127.0.0.1 vs 0.0.0.0)
  • 防火墙或代理主动拒绝了连接
powershell
# 确认端口确实没人监听
Test-NetConnection localhost -Port 4321
# TcpTestSucceeded: False → 确实没人监听

# 检查服务进程是否还活着
Get-Process -Name node -ErrorAction SilentlyContinue

"Permission denied" (Linux)

bash
# 绑定 1024 以下的端口通常需要 root 或 CAP_NET_BIND_SERVICE
# 开发环境优先使用 8080 等高端口;生产环境通常由反向代理监听 80/443
sudo lsof -nP -iTCP:80 -sTCP:LISTEN

# 确实需要时才给指定二进制设置 capability
node_path=$(readlink -f "$(command -v node)")
sudo setcap 'cap_net_bind_service=+ep' "$node_path"
getcap "$node_path"

# 这会影响所有经该 Node 二进制启动的程序;不再需要时移除
sudo setcap -r "$node_path"

TIME_WAIT 堆积

TIME_WAIT 是已关闭 TCP 连接的状态,通常出现在主动关闭连接的一方。它保护的是旧连接的四元组,不表示整个本地端口被统一锁定,也不必然阻止服务重新监听。

powershell
# 查看 TIME_WAIT 状态的连接
Get-NetTCPConnection -State TimeWait | Where-Object LocalPort -eq 4321

# 排障时同时查看本地/远程地址和端口,确认是哪一批连接
Get-NetTCPConnection -State TimeWait |
  Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort
bash
# Linux 查看 TIME_WAIT 连接
ss -tan state time-wait

不要为了 TIME_WAIT 修改 net.ipv4.tcp_fin_timeout:该参数控制的是孤立连接在 FIN_WAIT_2 状态停留的时间,并不解决 TIME_WAIT。开发服务重启失败时,应先确认是否仍有监听进程、是否绑定了相同地址,以及应用是否正确配置了 socket 重用。

多个进程监听同一端口?

同一协议、地址和端口通常只有一个监听 socket,但以下情况可能看到多个进程或多条记录:

  • 父进程把同一个监听 socket 继承给子进程
  • 程序使用了 SO_REUSEPORT
  • IPv4 和 IPv6 分别监听
  • 同一端口分别绑定在不同的本地地址上
powershell
# 查看是不是 IPv4/IPv6 各一个
Get-NetTCPConnection -LocalPort 4321 -State Listen |
  Select-Object LocalAddress, LocalPort, OwningProcess
# 0.0.0.0:4321 和 [::]:4321 是两条不同地址族的监听记录;
# 是否属于同一程序要以 OwningProcess 为准

推荐的个人习惯

  1. 开发前:先查一下目标端口有没有监听者 → Get-NetTCPConnection -LocalPort 4321 -State Listen
  2. 开发中:服务起不来先排查端口 → 看报错信息里的 EADDRINUSE
  3. 开发后:确认服务正常停止 → Test-NetConnection localhost -Port 4321 应该返回 False
  4. 写脚本时:启动服务后加 wait_port 确认就绪再继续后续操作

官方参考