Python не может связаться с подпроцессом сервера Minecraft - PullRequest
19 голосов
/ 31 января 2011

Я пытаюсь написать обработчик / контроллер для сервера 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()

1 Ответ

2 голосов
/ 08 сентября 2015

Я понятия не имею, как работает сервер Minecraft, но есть ряд проблем с вашим кодом:

  • Вы перенаправляете stderr на стандартный вывод из созданного процесса Java, а затем ожидаете ответ от сервера на строку. Это может быть причиной того, что сервер Minecraft не запускается, поскольку он блокирует запись stderr (в зависимости от того, как Windows XP обрабатывает его) . Кроме того, любая запись stderr (например, запись в журнал) уничтожит любые структурированные ответы, которые вы можете ожидать.

  • Вы читаете с sock.recv(N), а затем предполагаете, что вы получите весь кусок (например, пароль). Это не так, как работает TCP, вы можете получить только один символ назад (особенно если пользователь вводит пароль в интерактивном режиме, например, в приглашении Telnet).

  • Вы очищаете стандартный вывод подпроцесса , который является вашим входным потоком . Вы, вероятно, хотите очистить stdin подпроцесса. Сброс входного потока не имеет смысла, это выходной поток, который определяет, когда очищать.

...