简体   繁体   English

Python子流程因交互而挂起

[英]Python subprocess hangs on interaction

I am trying to write a minecraft server wrapper that allows me to send it commands and receive output. 我正在尝试编写一个我的世界服务器包装器,使我可以向它发送命令并接收输出。 Eventually, I'll attach a socket interface so that I can control my home server remotely to restart / second commands / etc. 最终,我将附加一个套接字接口,以便可以远程控制我的家庭服务器以重新启动/第二个命令/等等。

To this end, I am attempting to use the python subprocess module to start the server, then send commands and receive the output of the server. 为此,我尝试使用python子进程模块启动服务器,然后发送命令并接收服务器的输出。 Right now, I am running into an issue I can grab the output of the server and reflect it to screen, but the very first command I send to the process freezes the whole thing and I have to kill it. 现在,我遇到了一个问题,我可以获取服务器的输出并将其反映到屏幕上,但是我发送给进程的第一个命令冻结了整个过程,因此我必须杀死它。 It should be noted that I have attempted to remove the process.communicate line and instead replaced it with a print(command). 应该注意的是,我试图删除process.communicate行,而用print(command)代替。 This also froze the process My very basic current code is as follows: 这也冻结了过程。我非常基本的当前代码如下:

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()

Any help offered would be greatly appreciated! 提供的任何帮助将不胜感激!

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

Interact with process: Send data to stdin. 与进程交互:将数据发送到stdin。 Read data from stdout and stderr, until end-of-file is reached. 从stdout和stderr读取数据,直到到达文件末尾。 Wait for process to terminate . 等待进程终止

And in your case it's doing exactly that. 在您的情况下,它正是这样做的。 What you want to do instead of waiting for the process to be terminated is to interact with the process so, much like you're reading from the STDOUT stream directly in your listen() function, you should write to the process STDIN in order to send it commands. 您想要做的而不是等待流程终止的方法是与该流程进行交互,因此,就像您直接在listen()函数中从STDOUT流中读取一样,您应该写入流程STDIN以便发送命令。 Something like: 就像是:

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()

The problem with this approach, however, is that you'll have a potential of overwriting the server's output with your Enter command: prompt and that the user will end up typing the command over the server's output instead in the 'prompt' you've designated. 但是,这种方法的问题在于,您可能会用Enter command:提示符覆盖服务器的输出,并且用户最终将在服务器的输出上键入命令,而不是在输入的“提示”中输入指定的。

What you might want to do instead is to parse your server's output in the listen() function and then based on the collected output determine when the wrapped server expects user input and then, and only then, call the talk() function (of course, remove the while loop from it) to obtain user input. 相反,您可能想做的是在listen()函数中解析服务器的输出,然后根据收集的输出确定包装的服务器何时需要用户输入,然后才调用talk()函数(当然,从中删除while循环)以获取用户输入。

You should also pipe-out STDERR as well, in case the Minecraft server is trying to tell you something over it. 如果Minecraft服务器试图通过它告诉您一些信息,您还应该同时输出STDERR。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM