Python子流程在交互时挂起

时间:2017-12-10 06:17:53

标签: python multithreading

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

为此,我试图使用python子进程模块启动服务器,然后发送命令并接收服务器的输出。现在,我遇到了一个问题,我可以抓住服务器的输出并将其反映到屏幕上,但是我发送给进程的第一个命令会冻结整个过程,我必须将其杀掉。 应该注意的是,我试图删除process.communicate行,而是用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()

非常感谢任何提供的帮助!

1 个答案:

答案 0 :(得分:0)

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

  

与流程交互:将数据发送到stdin。从stdout和stderr读取数据,直到达到文件结尾。 等待进程终止

在你的情况下,它正是这样做的。您想要做什么而不是等待进程终止是与进程交互所以,就像您直接在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()函数中解析服务器的输出,然后根据收集的输出确定包装服务器何时需要用户输入,然后只调用{{ 1}}函数(当然,从中删除while循环)以获取用户输入。

如果Minecraft服务器试图通过它告诉你一些东西,你也应该也管出STDERR。