首页 > 解决方案 > 使用子进程控制 Minecraft 服务器

问题描述

我在我的 PC 上为朋友运行了一些经过改装的 Minecraft 服务器,我正在尝试构建一个程序,使启动它们并向它们发送命令变得更加容易。

我使用 bat 文件启动服务器并且能够subprocess做到这一点没有问题,但我不确定如何着手添加通过控制台向服务器发出命令的功能。

我考虑过stdin.write()在交互式控制台中使用它,它的效果很好。问题是当我将它添加到代码中时,它甚至在服务器启动之前执行停止命令,因此服务器永远不会停止。我曾尝试在单独的函数中执行此操作,但这也不起作用。

到目前为止,这是我的代码:

类文件:

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):
        server = subprocess.Popen(self.server_start_bat, cwd=self.dir, shell=True, stdin=subprocess.PIPE, text=True)
        server.communicate()


    def stop_server(self):
        server = subprocess.Popen(self.server_start_bat, cwd=self.dir, shell=True, stdin=subprocess.PIPE, text=True)
        server.stdin.write('stop\n')


    def command(self, command):
        server = subprocess.Popen(self.server_start_bat, cwd=self.dir, shell=True, stdin=subprocess.PIPE, text=True)
        self.command = command
        server.stdin.write(f'{self.command}\n')

简单的 GUI 我运行它:

from tkinter import *

import Servers

server = Servers.Server('path\\to\\bat\\file\\batfile.bat', 'dir\\to\\run\\command\\in')

main = Tk()
main.title('Server Commander')
server_title = Label(main, text="server, hosted on port ")
server_title.pack()
server_start = Button(main, text='Start', command=server.start_server)
server_start.pack()
server_stop = Button(main, text='Stop', command=server.stop_server)
server_stop.pack()

main.mainloop()

标签: pythonpython-3.xsubprocess

解决方案


有两个问题,我觉得:

  1. stop_server并且command每个都启动一个新的子流程,这应该只在start_server.

  2. start_server使用server.communicate()which 阻塞直到子进程完成,防止程序在运行时向服务器发送任何其他命令。

反而,

  • start_server应该创建子进程,然后将其存储在可以通过stop_serverand访问的变量中command
  • server.communicate应该在stop_server.

stop_server也只是 的一个特例command

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, text=True)

    def stop_server(self):
        self.command('stop')
        self.server.communicate()

    def command(self, command):
        self.server.stdin.write(f'{command}\n')

推荐阅读