2017-12-10 18 views
0

コマンドを送信して出力を受け取ることができるミニクラフトサーバーラッパーを作成しようとしています。最終的には、私はホーム・サーバをリモートで制御して/ secondコマンドを再起動するようにソケット・インタフェースを付けます。Pythonのサブプロセスが対話でハングする

このため、私は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() 

提供するすべてのヘルプをいただければ幸いです。また、これは次のように私の非常に基本的な現在のコードがあるプロセスを凍結しました!

答えて

0

subprocess.Popen.communicate()ドキュメントは明確に述べて:

は、プロセスとの対話:標準入力にデータを送信します。ファイルの終わりに達するまで、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()関数で解析し、収集した出力に基づいて、ラップされたサーバーがユーザー入力を予期してから、そのときだけtalk()関数を呼び出すことができます、それからwhileループを削除して)ユーザー入力を取得します。

また、Minecraftサーバーがあなたに何かを伝えようとしている場合に備えて、STDERRもパイプアウトする必要があります。

関連する問題