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

如何将Linux进程stdout重定向至多个TCP连接?

问题分析与解决方案

核心问题

你需要将一个进程的stdout输出完整转发给所有接入指定TCP端口的连接,但测试socat时发现数据被分流到不同连接,每个连接只能拿到部分内容——这是因为socat的fork模式是将输入流分流给子进程,而非复制流给所有连接,不符合你的需求。

方案一:用现有命令行工具组合实现

通过命名管道+tee+socat的组合可以实现流复制,步骤如下:

  1. 创建临时目录存放命名管道:
mkdir -p /tmp/tcp-broadcast
  1. 启动socat监听端口,为每个新连接创建独立的命名管道:
socat TCP-LISTEN:8080,reuseaddr,fork EXEC:'mkfifo /tmp/tcp-broadcast/fifo-$$; cat /tmp/tcp-broadcast/fifo-$$; rm /tmp/tcp-broadcast/fifo-$$'
  1. 将工作进程输出通过tee复制到所有存在的命名管道:
# 替换成你的实际工作进程命令
for i in {0..10000}; do echo "round ${i}"; sleep 1; done | tee /tmp/tcp-broadcast/fifo-*

注意事项

  • 若在tee启动后有新连接接入,需重启tee才能让新连接的管道被包含进去,因为tee启动时只会读取当时存在的管道列表。

方案二:自制Python转发脚本

如果需要支持动态添加连接(后续接入的连接也能接收之后的完整输出),用Python脚本更灵活,以下是实现代码:

import socket
import threading
import sys

LISTEN_PORT = 8080
client_connections = []
conn_lock = threading.Lock()

def broadcast_to_clients(data):
    """将数据广播给所有活跃客户端"""
    with conn_lock:
        # 遍历副本避免修改列表时出错
        for conn in client_connections[:]:
            try:
                conn.sendall(data)
            except Exception:
                # 连接失效,移除并关闭
                client_connections.remove(conn)
                conn.close()

def handle_client(conn):
    """保持连接,检测客户端是否在线"""
    try:
        # 空循环检测连接状态,收到空数据表示客户端断开
        while conn.recv(1024):
            pass
    finally:
        with conn_lock:
            if conn in client_connections:
                client_connections.remove(conn)
        conn.close()

def read_stdout():
    """读取标准输入并触发广播"""
    while True:
        line = sys.stdin.readline()
        if not line:
            break
        broadcast_to_clients(line.encode('utf-8'))

def main():
    server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_sock.bind(('0.0.0.0', LISTEN_PORT))
    server_sock.listen(5)

    # 启动stdout读取线程
    threading.Thread(target=read_stdout, daemon=True).start()

    print(f"Listening on port {LISTEN_PORT}...")
    while True:
        conn, addr = server_sock.accept()
        print(f"New connection from {addr}")
        with conn_lock:
            client_connections.append(conn)
        threading.Thread(target=handle_client, args=(conn,), daemon=True).start()

if __name__ == "__main__":
    main()

使用方法

  1. 保存脚本为stdout-broadcast.py
  2. 运行工作进程并将输出管道到脚本:
# 替换成你的实际工作进程命令
for i in {0..10000}; do echo "round ${i}"; sleep 1; done | python stdout-broadcast.py
  1. 用nc localhost 8080连接,所有连接都会收到完整输出,后续接入的连接也能获取之后的所有内容。

总结

  • 无需动态添加连接时,用命名管道+tee+socat的组合可以快速实现,无需编写代码。
  • 需要支持动态连接时,自制Python脚本是更可靠的选择。

内容的提问来源于stack exchange,提问作者Olli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:47:32