Python 子进程挂在交互上



我正在尝试编写一个 minecraft 服务器包装器,允许我向其发送命令并接收输出。最终,我将附加一个套接字接口,以便我可以远程控制我的家庭服务器以重新启动/第二个命令/等。

为此,我尝试使用 python 子进程模块来启动服务器,然后发送命令并接收服务器的输出。现在,我遇到了一个问题,我可以抓取服务器的输出并将其反映到屏幕上,但是我发送到进程的第一个命令冻结了整个事情,我必须杀死它。应该注意的是,我试图删除process.communication行,而是用print(命令)替换它。这也冻结了进程我当前最基本的代码如下:

from subprocess import Popen, PIPE
from threading import Thread
import threading
def listen(process):
while process.poll() is None:
output = process.stdout.readline()
print(str(output))
def talk(process):
command = input("Enter command: ")
while command != "exit_wrapper":
#freezes on first send command
parse_command(process, command)
command = input("Enter command: ")
print("EXITTING! KILLING SERVER!")
process.kill()
def parse_command(process, command):
process.communicate(command.encode())
def main():
process = Popen("C:\Minecraft Servers\ServerStart.bat", cwd = "C:\Minecraft Servers\", stdout=PIPE, stdin=PIPE)
listener = Thread(None, listen, None, kwargs={'process':process})
listener.start()
talker = Thread(None, talk, None, kwargs={'process':process})
talker.start()
listener.join()
talker.join()
if __name__ == "__main__":
main()

任何提供的帮助将不胜感激!

subprocess.Popen.communicate()文档明确指出:

与进程交互:将数据发送到标准。从标准输出和标准输出读取数据,直到到达文件末尾。等待进程终止

在你的情况下,它正是这样做的。您要做的不是等待进程终止,而是与进程进行交互,因此,就像直接在listen()函数中读取 STDOUT 流一样,您应该写入进程 STDIN 以便向其发送命令。像这样:

def talk(process):
command = input("Enter command: ")
while command != "exit_wrapper" and process.poll() is None:
process.stdin.write(command)  # write the command to the process STDIN
process.stdin.flush()  # flush it
command = input("Enter command: ")  # get the next command from user
if process.poll() is None:
print("EXITING! KILLING SERVER!")
process.kill()

但是,这种方法的问题在于,您可能会用Enter command:提示符覆盖服务器的输出,并且用户最终将在服务器的输出上键入命令,而不是在您指定的"提示符"中键入命令。

您可能想要做的是在listen()函数中解析服务器的输出,然后根据收集的输出确定包装的服务器何时需要用户输入,然后,然后,然后,只有这样,调用talk()函数(当然,从中删除 while 循环)以获取用户输入。

您还应该通过管道传输 STDERR,以防 Minecraft 服务器试图告诉您一些事情。

最新更新