Python 无法与 Minecraft 服务器的子进程通信

问题描述 投票:0回答:2

我正在尝试为 Minecraft 服务器编写一个处理程序/控制器。我的问题是我似乎无法正常写作和阅读。当客户端发出使用服务器类方法

serverCom
的命令时,Minecraft 服务器的文本/日志开始进入 Python 窗口/Python 控制台,并且连接的客户端挂起。另外,似乎在我使用
Popen
后,Minecraft 服务器直到我写入服务器(又名
serverCom
方法)后才真正启动。如果有人想知道,
Popen
会转到打开 .jar 文件的批处理文件。这是在 Windows XP 上。

import subprocess
import os
import configobj
import socket
import threading
from time import sleep

config = configobj.ConfigObj("config.ini")
cHost = config["hostip"]
cPort = int(config["hostport"])
cBuffer = int(config["serverbuffer"])
cClients = int(config["numberofclients"])
cPassword = config["password"]

class server(object):
    def __init__(self):
        self.process = False
        self.folder = "C:\\servers\\minecraft-danny"
        self.max = configobj.ConfigObj("%s\\simpleserver.properties"%self.folder)["maxPlayers"]

    def serverStart(self):
        if not self.process:
            self.process = subprocess.Popen("java -Xmx1024m -Xms1024m -jar minecraft_server.jar nogui", cBuffer, None, subprocess.PIPE, subprocess.PIPE, subprocess.STDOUT, cwd = self.folder)
            return True
        return False

    def serverStop(self):
        if self.process:
            self.serverCom("stop")
            self.process = False
            return True
        return False

    def serverCom(self, text):
        if self.process:
            self.process.stdout.seek(2)
            self.process.stdin.write("%s\n"%text)
            self.process.stdin.flush()
            self.process.stdout.flush()
            return (str(self.process.stdout.readline()), True)
        return ("", False)

    def serverPlayers(self):
        if self.process:
            self.serverCom("list")
            x = self.serverCom(" ")[0].split(":")[3].replace("\n","").replace(" ","")
            if x == "":
                x = 0
            else:
                x = len(x.split(","))
            return (x, self.max)
        return (0,self.max)

serv = server()

def client(cnct, adr):
    global count
    try:
        dat = str(cnct.recv(cBuffer)).split(" ")
        ans = False
        if dat[0] == "start":
            print "Client %s:%s started the MC Server....."%(adr[0], adr[1])
            x = serv.serverStart()
            sleep(1)
            serv.serverCom(" ")
            serv.serverCom(" ")
            sleep(5)
            if x:
                ans = "Server is now online."
            else:
                ans = "Server is already online."
        elif dat[0] == "stop":
            print "Client %s:%s stopped the MC Server....."%(adr[0], adr[1])
            x = serv.serverStop()
            sleep(6)
            if x:
                ans = "Server is now offline."
            else:
                ans = "Server is already offline."
        elif dat[0] == "commun":
            print "Client %s:%s executed a command on the MC Server....."%(adr[0], adr[1])
            serv.serverCom(" ".join(dat[1:]))
            x = serv.serverCom(" ")
            if x[1]:
                ans = x[0]
            else:
                ans = "No return text, server is offline or not responding."
        elif dat[0] == "players":
            print "Client %s:%s recieved the player count from the MC Server....."%(adr[0], adr[1])
            pc = serv.serverPlayers()
            ans = "%s/%s"%(pc[0],pc[1])
        elif dat[0] == "help":
            print "Client %s:%s recieved the help list....."%(adr[0], adr[1])
            ans = "__________\nstart - Starts the server.\nstop - Stops the server.\ncommun <command> - Writes to server's console.\nplayers - Returns player count.\nhelp - Shows this help.\nclose - Closes client connections.\n__________"
        elif dat[0] == "close":
            pass
        else:
            ans = "Command '%s' is not valid."%dat[0]
        if ans:
            cnct.send("PASS")
            cnct.send("%s\n"%ans)
            threading.Thread(target = client, args = (cnct, adr,)).start()
        else:
            cnct.send("DICN")
            cnct.send("Connection to server closed.\n")
            cnct.close()
            print "Client %s:%s disconnected....."%(adr[0], adr[1])
            if count:
                count -= 1
    except:
        cnct.close()
        print "Client %s:%s disconnected..... "%(adr[0], adr[1])
        if count:
            count -= 1

print "-MC Server Control Server v0.0.1 BETA-"
print "Starting up server....."
print "Connecting to socket....."
count = 0
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.bind((cHost, cPort))
sck.listen(5)
print "Connected and listening on %s:%s....."%(cHost, cPort)
print "Setting up client listener, allowing %s clients to connect at a time....."%cClients
while True:
    for x in range(cClients):
        (cnct, adr) = sck.accept()
        print "Client %s:%s connected....."%(adr[0], adr[1])
        cnct.send("Welcome to MineCraft Server Control.\n\nPlease enter server control password.\n")
        ps = str(cnct.recv(cBuffer))
        if count < cClients:
            if ps == cPassword:
                cnct.send("CRRT")
                cnct.send("%s was correct.\nIf you need help type 'help'."%ps)
                count += 1
                threading.Thread(target = client, args = (cnct, adr,)).start()
            else:
                cnct.send("WRNG")
                cnct.send("%s wasn't the correct password, please try again."%ps)
                cnct.close()
                print "Client %s:%s rejected....."%(adr[0], adr[1])
        else:
            cnct.send("WRNG")
            cnct.send("Too many clients connected to MineCraft Server Control")
            cnct.close()
            print "Client %s:%s rejected....."%(adr[0], adr[1])

sck.close()
python subprocess minecraft
2个回答
2
投票

我不知道 Minecraft 服务器是如何工作的,但您的代码存在很多问题:

  • 您正在将 stderr 从创建的 Java 进程重定向到 stdout,然后期待来自服务器的线路响应。 这可能是 Minecraft 服务器未启动的原因,因为它会阻塞 stderr 写入(取决于 Windows XP 如何处理它)。此外,任何 stderr 写入(例如日志写入)都会破坏您可能正在等待的任何结构化响应。

  • 您正在使用

    sock.recv(N)
    阅读,然后假设您获得了整个块(例如密码)。这不是 TCP 的工作方式,您很可能只返回一个字符(如果用户以交互方式输入密码,例如在 Telnet 提示符中,尤其如此)。

  • 您正在刷新子进程的标准输出,这是您的输入流。您可能想刷新子进程的 stdin 。刷新输入流没有任何意义,输出流决定何时刷新。


0
投票

Idk,但如果是本地服务器,则可以使用 mcrcon 代替。在这里阅读他们的文档:https://github.com/barneygale/MCRcon

© www.soinside.com 2019 - 2024. All rights reserved.