這是相當困難的在這裏說,但我覺得你問的是如何:
- 在後臺啓動的程序。
- 發送輸入,就好像它來自控制檯上的用戶。
- 讀取它嘗試在控制檯上顯示給用戶的輸出。
- 與此同時,運行另一個執行其他任務的線程。
最後一個很容易;事實上,你主要是寫它,你只需要在某個地方添加一個thread1.start()
。
subprocess
模塊可讓您啓動程序並控制其輸入和輸出。如果你只想在所有輸入饋一次,等到它完成,然後再處理所有的輸出,但很明顯的是,這裏不是你的情況下,這是最簡單的,所以它更多的參與:
minecraft = subprocess.Popen(['java', 'path/to/minecraft_server.jar', '-other', 'args],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
我m將stdout和stderr合併成一個管道;如果你想單獨閱讀它們,或者發送stderr到/ dev/null,或者其他什麼,請參閱文檔;這很簡單。雖然我們在此做出假設,但我會假設minecraft_server
使用簡單的基於行的協議,其中每個命令,每個響應和每條信息消息都只有一行(即在1K以下的文本以\n
)。
現在,把它輸入,你只是這樣做:
minecraft.stdin.write('Make me a sandwich\n')
或者,在Python 3.X:
minecraft.stdin.write(b'Make me a sandwich\n')
要閱讀它的輸出,你這樣做:
response = minecraft.stdout.readline()
這就像一個普通的文件。但請注意,它的作用類似於二進制文件。在Python 2.x中,唯一的區別是換行符不會自動轉換,但在Python 3.x中,這意味着您只能編寫bytes
(和兼容對象),而不是str
s,並且您將收到bytes
。這有很好的理由,但是如果您想要獲取像文本文件那樣的管道,請參閱Frequently Used Arguments和Popen
Constructor下的universal_newlines
(可能還有bufsize
)參數。
而且,它就像一個阻止文件。對於一個普通的文件,這很少重要,但是對於一個管道來說,很可能以後會有數據,但是還沒有數據(因爲服務器還沒有寫入數據)。所以,如果還沒有輸出(或者沒有完整的產品線的價值,因爲我使用了readline()
),那麼您的線程就會阻塞,等待。
如果你不想這樣做,你可能想創建另一個線程來服務stdout。其功能實際上看起來很相似,你有什麼:
def listener():
for line in minecraft.stdout:
if line.strip() == "Server can't keep up!":
minecraft.stdin.write("Restart Universe\n")
現在,線程可以阻止所有的一天,沒有任何問題,因爲你的其他線程仍在繼續。
嘛,不太沒有問題。
首先它很難徹底關閉你的程序。
更嚴重的是,進程之間的管道具有固定的大小;如果你沒有足夠快地服務標準輸出,或者孩子服務的標準輸入速度不夠快,管道可能會阻塞。而且,就像我寫的東西一樣,如果stdin管道阻塞,我們將永遠被阻塞在那個stdin.write
中,並且不會到達下一個讀取的stdout
,這樣也可以阻止,並且突然之間我們都在等待彼此永遠。
你可以通過讓另一個線程來服務stdout來解決這個問題。 subprocess
模塊本身包含一個示例,在所有高級函數使用的Popen._communicate
函數中。 (請務必查看Python 3.3或更高版本,因爲早期版本存在錯誤。)
如果您使用的是Python 3.4+(或3.3,關閉PyPI的backport),則可以改爲使用asyncio
來重寫程序一個事件循環,並以與編寫基於反應器的網絡服務器相同的方式處理輸入和輸出。這就是2017年所有酷酷的孩子們都在做的事情,但在2014年年底,許多人仍然認爲這看起來很新,很可怕。
如果所有這聽起來像比你簽署了很多工作,你可能要考慮使用pexpect
,它封裝了很多繁瑣的細節,並做了一些簡化的假設是可能真的在你的情況。
你是什麼意思「從Python輸入到控制檯」?您想將輸入提供給'minecraft_server.jar',就像您的程序是其控制檯一樣?或者將真正的控制檯的stdin與服務器共享,並以某種方式在兩者之間進行多路複用,以便獲得用戶輸入?要麼…? – abarnert 2014-11-21 00:19:09
我想將輸入反饋到minecraft_server.jar,就好像我的程序在其控制檯中一樣。 @abarnert – TheMountainFurnaceGabriel 2014-11-21 00:34:19