无法修改原代码,如何获取subprocess/exec进程的本地端口?
解决方案
一、通用方案:基于psutil实时监控进程连接
针对Python调用场景,利用psutil库轮询进程的网络连接状态,直到找到目标主机的会话连接,提取本地端口。该方法适配macOS和Ubuntu:
import subprocess import psutil import time def get_local_port(target_host): # 启动目标子进程 process = subprocess.Popen(['curl', target_host]) proc = psutil.Process(process.pid) local_port = None timeout = 10 # 设置超时阈值,避免无限等待 start_time = time.time() # 轮询等待连接建立 while time.time() - start_time < timeout: try: # 适配macOS和Linux的psutil API差异 connections = proc.connections(kind='inet') if psutil.MACOS else proc.net_connections(kind='inet') for conn in connections: # 匹配目标主机的连接(处理带协议前缀的域名) target_addr = target_host.split('://')[-1] if '://' in target_host else target_host if conn.raddr and conn.raddr[0] == target_addr: # 筛选已建立或正在建立的连接 if conn.status in (psutil.CONN_ESTABLISHED, psutil.CONN_SYN_SENT): local_port = conn.laddr[1] break if local_port: break time.sleep(0.1) except psutil.NoSuchProcess: # 进程提前退出,终止轮询 break # 等待子进程执行完成 process.communicate() return local_port # 使用示例 port = get_local_port('www.example.com') print(f"本地端口: {port}")
二、macOS专属:用lsof工具抓取端口
如果是执行Bash脚本场景,可通过lsof工具直接筛选进程的网络连接:
#!/bin/bash TARGET_HOST="www.example.com" # 启动子进程并记录PID curl $TARGET_HOST & PID=$! TIMEOUT=10 START_TIME=$(date +%s) LOCAL_PORT="" # 轮询lsof结果提取端口 while [ $(($(date +%s) - START_TIME)) -lt $TIMEOUT ]; do LOCAL_PORT=$(lsof -p $PID -i TCP -s TCP:ESTABLISHED,SYN_SENT | grep $TARGET_HOST | awk '{print $9}' | cut -d':' -f2) if [ ! -z "$LOCAL_PORT" ]; then break fi sleep 0.1 done # 等待子进程结束 wait $PID echo "本地端口: $LOCAL_PORT"
三、Ubuntu专属:用ss工具高效查询
Linux下用ss工具替代netstat,更高效地关联进程与端口:
#!/bin/bash TARGET_HOST="www.example.com" # 启动子进程并记录PID curl $TARGET_HOST & PID=$! # 解析域名对应的IP,避免域名匹配问题 TARGET_IP=$(dig +short $TARGET_HOST | head -n1) TIMEOUT=10 START_TIME=$(date +%s) LOCAL_PORT="" # 轮询ss结果提取端口 while [ $(($(date +%s) - START_TIME)) -lt $TIMEOUT ]; do LOCAL_PORT=$(ss -tp state established,syn-sent '( dport = :80 or dport = :443 )' | grep $PID | awk '{print $4}' | cut -d':' -f2) if [ ! -z "$LOCAL_PORT" ]; then break fi sleep 0.1 done wait $PID echo "本地端口: $LOCAL_PORT"
关键注意事项
- 可根据实际请求类型(HTTP/HTTPS)调整目标端口筛选条件(80/443)。
- 若子进程存在嵌套fork的情况,需用
psutil的children(recursive=True)方法递归遍历所有子进程,再检查连接。 - 轮询间隔和超时时间可根据网络环境灵活调整,避免无效等待。
内容的提问来源于stack exchange,提问作者Adir Bruchim
相关产品推荐
相关产品推荐

