编辑:我在Windows上运行此程序,因为服务器是在我的主要游戏装备上管理的
我试图创建一个我的世界服务器控制器,以便我可以简化管理服务器的过程。我已经能够使用子进程启动和停止服务器而没有任何问题,但是当我尝试使其发出命令时,它不会。除非我subprocess.communicate()
对此解决方案使用问题,否则将导致脚本永久等待并最终崩溃,从而使服务器继续运行。这是我所拥有的代码。
import subprocess
class Server:
def __init__(self, server_start_bat, dir):
self.server_start_bat = server_start_bat
self.dir = dir
def start_server(self):
self.server = subprocess.Popen(self.server_start_bat, cwd=self.dir, shell=True, stdin=subprocess.PIPE,
universal_newlines=True, text=True)
def stop_server(self):
self.run_command('stop')
self.server.communicate()
def op_me(self):
self.run_command(f'op Username')
def clear_weather(self):
self.run_command(f'weather clear 1000000')
def mob_griefing_on(self):
self.run_command(f'gamerule mobGriefing True')
def mob_griefing_off(self):
self.run_command(f'gamerule mobGriefing True')
def set_time_day(self):
self.run_command(f'time set day')
def set_time_night(self):
self.run_command(f'time set night')
def run_command(self, command_text):
self.server.stdin.write(f'{command_text}\n')
编辑:在python的subprocess.PIPE上签出非阻塞读取
我当时正在与一个非常相似的问题作斗争,我花了3天的时间才能全部解决。subprocess.communicate的问题在于您只能调用一次,而子进程终止后似乎只能给出输出(根据我的经验,很可能是错误的)。
我所遇到的问题(您的问题imho可以归结为该问题):如何在仍在运行的标准输入中写入标准输入并从标准输出中读取?
我最终使用了Pipes。请注意,如果您编写的内容小于BUFSIZE(在我的情况下为0x1000),则必须对它们进行冲洗。请参阅man pipe
以获取更多信息。
无论如何,下面是我的代码。
import time
import pty
import os
import subprocess
PIPE_BUFSIZE = 4096
_control = False
class Pipe:
def __init__(self, flags=None, terminal=True):
"""Creates a Pipe you can easily write to and read from. Default is to open up a pseudo-terminal.
If you supply flags, pipe2 is used."""
if flags or not terminal:
self._readfd, self._writefd = os.pipe2(flags)
else: # default
self._readfd, self._writefd = pty.openpty()
self.readobj = open(self._readfd, "rb", 0)
self.writeobj = open(self._writefd, "wb", 0)
def write(self, text):
if isinstance(text, str):
text = text.encode()
result = self.writeobj.write(text)
self.writeobj.flush()
return result
def read(self, n):
if _control: # im not using this anymore since the flush seems to be reliable
controlstr = b"this_was_flushed"
controllen = len(controlstr)
self.writeobj.write(controlstr)
time.sleep(.001)
self.writeobj.flush()
result = self.readobj.read(n+controllen)
assert result[-controllen:] == controlstr
return result[:-controllen]
else:
self.writeobj.flush()
return self.readobj.read(n)
class ProcessIOWrapper:
"""Provides an easy way to redirect stdout and stderr using pipes. Write to the processes STDIN and read from STDOUT at any time! """
def __init__(self, args, inittext=None, redirect=True):
#create three pseudo terminals
self.in_pipe = Pipe()
self.out_pipe = Pipe()
self.err_pipe = Pipe()
# if we want to redirect, tell the subprocess to write to our pipe, else it will print to normal stdout
if redirect:
stdout_arg= self.out_pipe.writeobj
stderr_arg= self.err_pipe.writeobj
else:
stdout_arg=None
stderr_arg= None
self.process = subprocess.Popen(args, stdin=self.in_pipe.readobj, stdout=stdout_arg, stderr=stderr_arg)
def write(self, text):
return self.in_pipe.write(text)
def read(self, n, start=None):
return self.out_pipe.read(n)
我用于测试的小型C程序(也用于其他程序)
#include <stdio.h>
int main(){
puts("start\n");
char buf[100]="bufbufbuf";
while(1){
gets(buf);
for (int i=0; i<strlen(buf); i++)
if (i%2==0) buf[i]+=1;
puts(buf);
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句