You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法修改原代码,如何获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 00:05:07