[英]how can I write to a processes stdin and read from its stdout while it is still running?
Edit: I am running this on windows as the servers are administered on my main gaming rig编辑:我在 Windows 上运行它,因为服务器是在我的主要游戏装备上管理的
I am trying to create a minecraft server controller so that I can streamline the process of administering servers.我正在尝试创建一个 minecraft 服务器控制器,以便我可以简化管理服务器的过程。 I have been able to use subprocess to start and stop the server with no issues however when I try to get it to issue commands It will not.
我已经能够使用子进程来启动和停止服务器而没有任何问题,但是当我尝试让它发出命令时它不会。 Unless I use
subprocess.communicate()
the problem with this solution however is that it causes the script to wait forever and eventually crash, leaving the server running.除非我使用
subprocess.communicate()
但是这个解决方案的问题是它导致脚本永远等待并最终崩溃,使服务器运行。 Here is the code for what I have.这是我所拥有的代码。
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')
Edit: Check out Non-blocking read on a subprocess.PIPE in python编辑: 在 python 中查看subprocess.PIPE 上的非阻塞读取
I was battling a very similar issue and it took me 3 days to get it all running.我正在与一个非常相似的问题作斗争,我花了 3 天的时间才让它全部运行。 The problem with subprocess.communicate is that you can only call it once, and the output seems to be given only once the subprocess terminates (in the experience i had, could very well be wrong).
subprocess.communicate 的问题是你只能调用它一次,并且输出似乎只在子进程终止时给出(根据我的经验,很可能是错误的)。
The question i had, which your question imho boils down to was: how can I write to a processes stdin and read from its stdout while it is still running?我的问题,你的问题恕我直言归结为:我如何写入进程标准输入并在它仍在运行时从它的标准输出中读取?
I ended up using Pipes.我最终使用了管道。 Note that they have to me flushed if you write something that is smaller that BUFSIZE, which is 0x1000 in my case.
请注意,如果您编写的内容小于 BUFSIZE(在我的情况下为 0x1000),则它们必须刷新。 See
man pipe
for more info.有关更多信息,请参阅
man pipe
。
Anyway, below is my code.无论如何,下面是我的代码。
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)
Small C Program i used for testing (used others, too)我用于测试的小 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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.