Python脚本内无法向子进程Popen.stdin写入?进程组问题排查
问题原因与解决方法
核心原因分析
1. 子进程未读取父进程创建的管道stdin
Terraria服务器这类交互式程序默认需要连接**终端(TTY)**才能接收命令,而非从父进程通过subprocess.Popen创建的管道读取输入。当你用stdin=subprocess.PIPE启动子进程时,程序会因未关联真实终端进入非交互式模式,完全忽略管道输入,因此直接调用server_process.stdin.write()毫无反应。
2. 同进程组内/proc/PID/fd/0不存在的原因
子进程启动后会主动关闭父进程创建的管道fd(fd 0),重新打开终端设备作为标准输入。但在父进程的上下文里,server_process.pid对应的/proc/[pid]/fd/0可能还未完成更新,或已被关闭,导致用os.system写入时提示路径不存在。而外部Bash执行时,子进程已完成终端关联,/proc/[pid]/fd/0指向真实终端设备,因此写入有效。
解决办法
要让Python脚本正常向Terraria服务器发送命令,需让子进程关联伪终端(PTY),模拟真实终端环境:
方法1:使用pexpect库(推荐)
pexpect专门用于处理交互式子进程,自动模拟终端:
import pexpect # 启动服务器并关联伪终端 server_process = pexpect.spawn("my_executable arg1 arg2") # 发送exit命令(自动添加换行) server_process.sendline('exit')
方法2:使用标准库pty模块
手动创建伪终端关联子进程:
import subprocess import pty import os # 创建主从伪终端对 master_fd, slave_fd = pty.openpty() # 让子进程的标准输入/输出/错误都关联到从终端 server_process = subprocess.Popen( "my_executable arg1 arg2", stdin=slave_fd, stdout=slave_fd, stderr=slave_fd, text=True ) # 关闭从终端的父进程引用 os.close(slave_fd) # 向主终端写入exit命令 os.write(master_fd, b'exit\n')
内容的提问来源于stack exchange,提问作者pipsqueaker117
相关产品推荐
相关产品推荐

