2011-01-31 8 views
19

Sto provando a scrivere un gestore/controller per il server Minecraft. Il mio problema è che non riesco a scrivere e leggere per funzionare correttamente. Quando un client emette un comando che utilizza il metodo della classe server serverCom, il testo/log del server Minecraft inizia a entrare nella finestra Python/console Python e il client connesso si blocca. Inoltre, sembra che dopo aver usato Popen, il server Minecraft non si avvii realmente fino a quando non scrivo sul server (ovvero il metodo serverCom). Nel caso qualcuno si stia chiedendo, lo Popen va a un file batch che apre il file .jar. Questo è su Windows XP.Python non può comunicare con il sottoprocesso di un server 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

posso consigliarti [Python's PEP8: Style Guide for Python Code] (http://www.python.org/dev/peps/pep-0008/)? – orftz

+1

Sembra che dovresti usare comunicare() per comunicare. [Questa domanda] (http://stackoverflow.com/questions/163542) dovrebbe aiutarti a tenere a bada gli zombi. – pwan

+0

Non sono riuscito a capire "sottoprocesso", quindi ho pensato a me stesso cosa fosse "asincrono e non bloccante" e mi ha colpito, [Twisted] (http://twistedmatrix.com/trac/)! Greg ha qui una [domanda interessante] (http://stackoverflow.com/questions/6105760/twisted-python-spawnprocess-getting-output-from-a-command) [ecco come implementare un wrapper di processo] (http: //twistedmatrix.com/trac/browser/tags/releases/twisted-10.0.0//twisted/runner/procmon.py#L52) [Buona fortuna] [minecraft.py]! [minecraft.py]: https://github.com/YellowOnion/minecraft.py/blob/master/minecraft.py –

risposta

2

Non ho idea di come funziona un server di Minecraft, ma ci sono una serie di problemi con il tuo codice:

  • si reindirizzano stderr allo stdout dal processo Java creato, quindi in attesa di un risposta di linea dal server. Questo potrebbe essere il motivo per cui il server Minecraft non si avvia, dal momento che potrebbe bloccare su una scrittura stderr (a seconda di come viene gestito da Windows XP). Inoltre, qualsiasi stderr write (ad esempio, log write) distruggerà qualsiasi risposta strutturata che si stia aspettando.

  • Si sta leggendo con sock.recv(N) e quindi si presuppone che si ottiene l'intero blocco (ad esempio la password). Questo non è il modo in cui funziona TCP, si potrebbe benissimo ottenere solo un carattere indietro (specialmente vero se l'utente digita la password in modo interattivo, ad esempio in un prompt Telnet).

  • Si sono vampate di calore lo stdout del sottoprocesso, che è il vostro ingresso flusso. Probabilmente si desidera svuotare lo stdin del sottoprocesso. Il flussaggio di un flusso di input non ha senso, è il flusso di output che determina quando eseguire il flush.

Problemi correlati