2011-01-31 12 views
19

Próbuję napisać handler/kontroler dla serwera Minecraft. Moim problemem jest to, że nie mogę sprawić, by pisanie i czytanie działały prawidłowo. Gdy klient wydaje polecenie, które używa metody klasy serwera serverCom, tekst/dziennik serwera Minecraft wchodzi do konsoli Python/Python i zawieszony jest podłączony klient. Wydaje się również, że po użyciu Popen serwer Minecraft nie uruchamia się tak długo, dopóki nie napiszę na serwer (inaczej: metoda serverCom). Jeśli ktoś się zastanawia, Popen przechodzi do pliku wsadowego, który otwiera plik .jar. To jest w systemie Windows XP.Python nie może komunikować się z podprocessem serwera Minecraft

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() 
+9

Czy mogę Ci doradzić [Python's PEP8: Style Guide for Python Code] (http://www.python.org/dev/peps/pep-0008/)? – orftz

+1

Wygląda na to, że powinieneś używać komunikacji() do komunikowania się. [To pytanie] (http://stackoverflow.com/questions/163542) powinno pomóc w utrzymaniu zombi na dystans. – pwan

+0

Nie mogłem wymyślić "podprocesu", więc pomyślałem sobie, co jest "asynchroniczne i nie blokujące" i uderzyło mnie, [Twisted] (http://twistedmatrix.com/trac/)! Greg ma tutaj [interesujące pytanie] (http://stackoverflow.com/questions/6105760/twisted-python-spawnprocess-getting-output-from-a-ommandand) [tutaj, w jaki sposób wdrożyć opakowanie procesu] (http: //twistedmatrix.com/trac/browser/tags/releases/twisted-10.0.0//twisted/runner/procmon.py#L52) [Powodzenia] [minecraft.py]! [Minecraft.py]: https://github.com/YellowOnion/minecraft.py/blob/master/minecraft.py –

Odpowiedz

2

nie mam pojęcia, jak działa serwer Minecraft, ale istnieje szereg problemów z kodem:

  • Przekierowanie stderr do stdout z utworzonego procesu Java, następnie spodziewa się odpowiedź linii z serwera. Może to być przyczyną, dla której serwer Minecraft nie uruchamia się, ponieważ blokowałby on podczas zapisu stderr (w zależności od tego, jak system Windows XP go obsługuje). Dodatkowo każde zapisanie stderr (np. Zapis logu) zniszczy wszelkie strukturalne odpowiedzi, na które możesz czekać.

  • Czytasz z sock.recv(N), a następnie zakładając, że otrzymujesz cały fragment (np. Hasło). Nie jest tak, jak działa TCP, możesz bardzo dobrze odzyskać tylko jeden znak (zwłaszcza jeśli użytkownik wpisuje hasło interaktywnie, np. W wierszu Telnet).

  • Jesteś spłukiwanie stdout podproces, który jest Twój wkład strumień. Prawdopodobnie chcesz opróżnić podprocesor stdin. Płukanie strumienia wejściowego nie ma sensu, to strumień wyjściowy określa, kiedy należy przepłukać.

Powiązane problemy