如何在仍在运行的标准输入中写入进程标准输入并从其标准输出中读取?

萨米·里格登496

编辑:我在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')
python00b

编辑:在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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何从标准输入中读取进程替换?

如何写入正在运行的程序的标准输入

如何在Emacs中写入标准输出

如何从标准输入中读取无阻塞?

如何在Groovy脚本中从Bash Heredoc读取标准输入

在python中检查正在运行的子进程的标准输出

Python子进程:提供标准输入,读取标准输出,然后提供更多标准输入

写入子进程的标准输入

X86从标准输入读取并写入标准输出,而无需引用标准库

bash脚本如何从管道中写入其标准输出?

Swift:如何在不等待进程完成的情况下读取子进程中的标准输出

如何从bash中的子进程实时读取标准输出

写入正在运行的Docker容器的标准输入

在FreeBSD / macOS下获取正在运行的进程的标准输入/输出

如何将python程序的标准输出输入到Popen标准输入中?

如何从正在运行的Docker容器中读取文件和标准输出

在 bash 脚本中重定向标准输入和标准输出

读取正在等待输入的生成进程的标准输出

如何在 dart 中输入标准输入并中断空格?

在Python中,如何从标准输入读取数据,直到管道进程终止?

如何在汇编中逐个字符地从标准输入读取输入

关闭标准输出或标准输入

从Rust中的标准输入读取原始字节

Shell脚本-从标准输入与文件中读取

在Bash管道中读取标准输入

从标准输入中读取任意数量的行

从标准输入中读取地图密钥

在J中读取多行标准输入

golang从标准输入中读取长文本