Python can't communicate with subprocess of a Minecraft server - python

I'm trying to write a handler/controller for the Minecraft server. My problem is that I can't seem get writing and reading to work properly. When a client issues a command that uses the server class's method serverCom, the Minecraft server's text/log starts to come into the Python window/Python console and the connected client hangs. Also, it seems that after I use Popen, the Minecraft server doesn't really launch until I do write to the server (aka serverCom method). In case anyone is wondering, the Popen goes to a batch file that opens the .jar file. This is on 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()

I have no idea how a Minecraft server works, but there are a number of problems with your code:
You are redirecting stderr to stdout from the created Java process, then expecting a line response from the server. This could be the reason that the Minecraft server is not starting, since it would block on a stderr write (depending on how Windows XP handles it). Additionally, any stderr write (e.g. log write) will destroy any structured responses you may be waiting for.
You are reading with sock.recv(N) and then assuming that you get the whole chunk (e.g. password). This is not how TCP works, you may very well get just one character back (especially true if the user types the password interactively e.g. in a Telnet prompt).
You are flushing the stdout of the subprocess, which is your input stream. You probably want to flush the stdin of the subprocess. Flushing an input stream makes no sense, it is the output stream that determines when to flush.

Related

Python script stuck at queue.join()

I am trying to implement a server for handling many clients (from thenewboston python reverse shell tutorials). I have the exact same code but when i run the script it gets stuck at queue.join(). How to make it work? I am unable to figure it out.
Here is the code
import socket
import sys
import threading
from queue import Queue
NUMBER_OF_THREADS = 2
JOB_NUMBER = [1, 2]
queue = Queue()
all_connections = []
all_addresses = []
# thread 1
# create socket (allows two computers to connect)
def socket_create():
try:
global host # ip address of the server
global port # port is to identify the kind of data
global s
host = ''
port = 9999
s = socket.socket()
except socket.error as msg:
print("Socket creation error: " + str(msg))
return
# bind socket to port and wait for connection from client
def socket_bind():
try:
global host
global port
global s
print("Binding socket to port: " + str(port))
s.bind((host, port))
s.listen(5)
# 5 is the no. of conections that can be made before server starts rejecting other requests
except socket.error as msg:
print("Socket binding error: " + str(msg) + "\n" + "Retrying...")
socket_bind()
return
# accept connections from multiple clients and save to list
def accept_connections():
for c in all_connections:
c.close()
del all_connections[:]
del all_addresses[:]
while 1:
try:
conn, address = s.accept()
conn.setblocking(1)
all_connections.append(conn)
all_addresses.append(address)
print("\nConnection has been establish: " + address[0])
except:
print("Error accepting connections")
return
# thread 2
# custom command promt for sending commands remotely
def start_turtle():
while True:
cmd = input('turtle> ')
if cmd == 'list':
list_connections()
elif 'select' in cmd:
conn = get_target(cmd)
if conn is not None:
send_target_commands(conn)
else:
print("Command not recognized")
return
# listing all the connections with indexing in the custom promt
def list_connections():
results = ''
for i, conn in enumerate(all_connections):
try:
conn.send(str.encode(' '))
conn.recv(20480)
except:
del all_connections[i]
del all_addresses[i]
continue
results += str(i) + ' ' + str(all_addresses[i][0]) + ' ' + str(all_addresses[i][1]) + '\n'
print('-----Clients-----' + '\n' + results)
return
# select a target client
def get_target(cmd):
try:
target = cmd.replace('select ', '')
target = int(target)
conn = all_connections[target]
print("You are now connected to " + str(all_addresses[target][0]))
print(str(all_addresses[target][0]) + '> ', end="")
return conn
except:
print("Not a valid selection")
return None
return
# connect with remote target client
def send_target_commands(conn):
while True:
try:
cmd = input()
if len(str.encode(cmd)) > 0:
conn.send(str.encode(cmd))
client_response = str(conn.recv(20480), "utf-8")
print(client_response, end="")
if cmd == "quit":
break
except:
print("Connection was lost")
break
return
# create worker threads
def create_workers():
for _ in range(NUMBER_OF_THREADS):
t = threading.Thread(target=work)
t.daemon = True
t.start
return
# do the next job in the queue (one handles connections, other sends commands)
def work():
while True:
x = queue.get()
if x == 1:
socket_create()
socket_bind()
accept_connections()
if x == 2:
start_turtle()
queue.task_done()
return
# create jobs for later extracting them and assigning them to the threads
def create_jobs():
for x in JOB_NUMBER:
queue.put(x)
queue.join()
return
def main():
create_workers()
create_jobs()
if __name__ == '__main__':
main()
Since you are using infinite loops (while True) at start_turtle and (while 1) at accept_connections they are not returning.
Since they don't return the func work never calls queue.task_done(), so the queue stuck joining.
I'm afraid you need to do one of the following:
start both start_turtle and accept_connections in parallel processes or threads.
Be sure they should call the queue.task_done().
For instance, you may include the queue as parameter and call it before starting the infinite loops (second option).
def work():
while True:
x = queue.get()
if x == 1:
socket_create()
socket_bind()
accept_connections(queue) # call queue.task_done() there
if x == 2:
start_turtle(queue) # call queue.task_done() in start_turtle
return
def start_turtle(queue):
queue.task_done() # Join one item from the queue
while True:
cmd = input('turtle> ')
if cmd == 'list':
list_connections()
elif 'select' in cmd:
conn = get_target(cmd)
if conn is not None:
send_target_commands(conn)
else:
print("Command not recognized")
return
On the other hand, in your create_workers you don't call the start method of the thread so your workers didn't really start.
Perhaps this is a typo.
def create_workers():
for _ in range(NUMBER_OF_THREADS):
t = threading.Thread(target=work)
t.daemon = True
# t.start # Not starting the Thread
t.start() # You need to call the start method
return

Python threading lock on Raspberry Pi b+

I am fairly new to Python (and even more to Python 3) but I can't figure out what is the problem here.
My code is fairly simple and run on Raspberry B+.
It basically communicates with the socket interface of VLC. Here is the code of the thread:
class MyClientConn(threading.Thread):
def __init__(self, clientConn, ServerPath):
threading.Thread.__init__(self)
self.clConn = clientConn
self.clConn.settimeout(5.0)
self.ServPath = ServerPath
self.daemon = True
self.start()
def run(self):
self.clConn.send(b'Greeting\n')
try:
tmpb = b''
Connected = True
Cmd = b''
while (Connected) and (Cmd.rfind(b'\n') == -1): #Retrieve command sent from client
try:
tmpb = self.clConn.recv(1)
if len(tmpb) > 0:
Cmd += tmpb
except Exception as inst:
Connected = False
Cmd = b''
return
if Cmd == b'VLCcmd\n': #We need to pass a command to VLC
try:
VLCcmd = bytearray()
tmpb = b''
Connected = True
while (Connected) and (VLCcmd.rfind(b'\n') == -1): #We retrieve the command to send to VLC
tmpb = self.clConn.recv(1)
if len(tmpb) > 0:
VLCcmd.extend(tmpb)
if len(tmpb) == 0:
Connected = False
vlcSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #Create socket to communicate with VLC
vlcSock.settimeout(2.0)
vlcSock.connect(('127.0.0.1',31514))
VLCrep = b''
tmpb = b''
Connected = True
while (Connected) and (VLCrep.rfind(b'> ') == -1): #Clear VLC Welcome message
tmpb = vlcSock.recv(1)
if len(tmpb) > 0:
VLCrep += tmpb
if len(tmpb) == 0:
Connected = False
vlcSock.send(VLCcmd) #Send command to VLC
Connected = True
VLCrep = b''
tmpb = b''
while (Connected) and (VLCrep.rfind(b'> ') == -1): #read VLC answer
tmpb = vlcSock.recv(1)
if len(tmpb) > 0:
VLCrep += tmpb
if len(tmpb) == 0:
Connected = False
self.clConn.send(VLCrep + b'\n') #send VLC answer to client
if (VLCcmd.find(b'get_time') == -1) and (VLCcmd.find(b'get_title') ==-1) and (VLCcmd.find(b'get_length')==-1) and (VLCcmd.find(b'playlist 2')==-1):
logging.debug('VLC Command: ' + VLCcmd.decode())
logging.debug('VLC Answer: ' + VLCrep.decode())
except Exception as inst:
logging.debug('VLCcmd error: ')
logging.debug(inst)
finally:
if 'vlcSock' in locals():
vlcSock.close()
Cmd = b''
return
except Exception as inst:
logging.debug('Error in Run: ')
logging.debug(inst)
finally:
self.clConn.close
And this is how it's called:
print ('Server path: ' + ServPath)
# Before to open a passive socket we check VLC socket is open
if CheckVLCI('127.0.0.1',31514):
print('VLC running, all good :)')
else:
print ('Could not connect to VLC. Exiting.')
raise SystemExit
TCPServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
TCPServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print ('Server socket created...')
TCPServer.bind((host, port))
if host == '':
print ('Server binded to interface: 0.0.0.0' + ' port: ' + str(port))
else:
print ('Server binded to interface: ' + host + ' port: ' + str(port))
TCPServer.listen(128)
while 1:
try:
conn, addr = TCPServer.accept()
MyClientConn(conn, ServPath)
except Exception as inst:
logging.debug('Main error:')
logging.debug(inst)
time.sleep(0.1)
TCPServer.close()
Just to let you know.
My client sends commands every 300 ms to the Python server in order to retrieve the position of the track played and so on.
What happens is that some threads just hang consumming 100% of CPU like if it was stuck in a loop (after X minutes or hours, it's really variable). But I have absolutly no exception raised and I am wondering if it's not happening in the Python interpreter more than the script itself.
It works perfectly on my desktop and any other x86_64 CPU with normal ressources (i3 to i7 and more than 2 Gb of RAM).
I have the feeling that the problem is more due to Python that doesn't cope well with low ressources than my script, but if anyone could tell me if I am doing something obviously wrong it will really make my day.
Thanks!

Python Socket Programming Client "quit not working

I made a simple Chat Server using Python. I'm having trouble quitting the program from the client side. When connected I need to be able to type "/quit" and the program should disconnect from both sides, client and server. here is my code:
alias= raw_input("Name: ")
print 'Connected to remote host. You can start sending messages'
sys.stdout.write(alias + '->'); sys.stdout.flush()
while 1:
socket_list = [sys.stdin, s]
# Get the list sockets which are readable
read_sockets, write_sockets, error_sockets =
select.select(socket_list , [], [])
for sock in read_sockets:
if sock == s:
# incoming message from remote server, s
data = sock.recv(4096)
print data
if not data :
print '\nServer has ended Connection'
sys.exit()
else :
#print data
sys.stdout.write(data)
sys.stdout.write(alias + '->'); sys.stdout.flush()
else :
# user entered a message
msg = alias + '->' + sys.stdin.readline()
quit = '/quit'
#print msg == quit
print
if msg is quit:
print "Goodbye"
s.close()
sys.exit()
else:
s.send(msg)
sys.stdout.write(alias + '->')
sys.stdout.flush()
Your line if msg is quit should be if msg == quit. is tests for identity, not equality. If you were testing if two objects were the same, you would use is here. However since you are comparing two strings, you must use ==.
Also, your msg variable is equal to alias + -> + readline. therefore "name -> /quit" will never equal '/quit'.

Socket issue when using threads

I've been working on a python game in my spare time, and I've run into a problem. I'm working with sockets using the basic threads module, and it works fine when I connect to the server file with one client. But more than that, and any that connect after the first freezes up the server and the first client.
Here is the code for the server
import socket
import random
import thread
from saveState import Save
from grid import Grid
import time
players = 0
save = Save()
grid = Grid()
def ready(c):
ready = raw_input("Are you ready to play?\n")
if(ready == "yes" or ready == "y"):
grid.makeGrid()
c.send("ready")
def clientThread(conn,players):
while True:
print "taking requests"
request = conn.recv(1024)
segments = request.split(",,")
if(segments[0] == "0" and players<200):
print "registering player", addr
serial = random.choice(list(range(999999)))
conn.send("{}".format(serial))
save.players[serial] = segments[2:]
print save.players[serial][9]
players+=1
elif(segments[0] == "3"):
if(segments[2] == "land"):
conn.send("{},,{},,{},,{}".format(grid.getLandType(int(save.players[serial][9]),int(save.players[serial][10])), grid.getDesc(int(save.players[serial][9]),int(save.players[serial][10])),int(save.players[serial][9]),int(save.players[serial][10])))
elif(segments[0]=="2"):
if(segments[2]=="playerX" and int(segments[3])==-1):
save.players[serial][9] = int(save.players[int(serial)][9])-1
elif(segments[2]=="playerX"):
save.players[serial][9] = int(save.players[int(serial)][9])+1
if(segments[2]=="playerY" and int(segments[3])==-1):
save.players[serial][10] = int(save.players[int(serial)][10])-1
elif(segments[2]=="playerY"):
save.players[serial][10] = int(save.players[int(serial)][10])+1
elif(segments[0]=="4"):
alreadySent = []
for m in grid.monsters:
if(m.X==save.players[int[segment[1]]][9] and m.Y==save.players[int[segment[1]]][10] and alreadySent[m]==False):
conn.send("{},,{}".format(m.name, True))
elif(time.clock == 60*60*(12+8)):
conn.send("{},,{}".format("You see the sun set on the horizon. Monsters will be more aggressive now.", False))
else:
print "sorry, there is an inconsistency in the request or the queue is full."
try:
#start up socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
name = socket.gethostbyname(socket.gethostname())
print name
port = input("select port\n")
s.bind((name, port))
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#listen for any attempts to connect to the api
#if anyone connects, give them a serial number and add their data to a storage file
while True:
s.listen(5)
c,addr = s.accept()
thread.start_new_thread(ready,(c,))
thread.start_new_thread(clientThread,(c, players))
conn.close
sock.close
except socket.error:
print " either the server port is closed or in use. try again"
and the client
import random
from grid import Grid
from player import Player
from descriptions import Descriptions
import socket
import time
import thread
description = Descriptions()
def descisionHandler(s,serial):
while True:
s.send("{},,{},,{}".format(3,serial,"land"))
response = s.recv(1024).split(",,")
print "you are on a {} tile \n {} \n {} \n {}".format(response[0], response[1],response[2], response[3])
action=raw_input("What Will You Do?\n")
try:
if(action == "west" and player.locX>0):
s.send("{},,{},,{},,{}".format(2,serial,"playerX",-1))
time.sleep(0.5)
elif(action == "east" and player.locX<199):
s.send("{},,{},,{},,{}".format(2,serial,"playerX",1))
time.sleep(0.5)
elif(action == "north" and player.locY>0):
s.send("{},,{},,{},,{}".format(2,serial,"playerY",-1))
time.sleep(0.5)
elif(action == "south" and player.locY<199):
s.send("{},,{},,{},,{}".format(2,serial,"playerY",1))
time.sleep(0.5)
# elif(action == "attack" and monster_data[1]):
# print "The {} wakes up! A battle begins!".format(monster_data[0])
elif(action == "profile"):
print " You are {} \n {} \n your role is {} \n you have an attack of {} \n a defense of {} \n a speed of {} \n and {} hitpoints \n attacks: {} \n you are located at {} {}".format(player.name,
player.backstory,player.role,player.attack,player.defense,player.speed, player.hitpoints, player.attacks, player.locX, player.locY)
elif(action == "exit"):
break
except IndexError:
pass
def eventHandler(s,serial):
while True:
s.send("{},,{}".format(4,serial))
response = s.recv(1024).split(",,")
print response[0]
return bool(response[1])
while True:
try:
print "\nWelcome to Overseer! We need a few things before we begin\n"
name = raw_input("What is your name?\n")
backstory = raw_input("What is in your past: choose one \n chosen \n magician \n poet\n")
role = raw_input("what is your class: choose one \n Warrior \n Mage \n Rougue \n Bard\n")
player = Player(name,description.player_backstory[backstory], role, 5,5,5,10, {"scrap": 10}, random.choice(list(range(200))), random.choice(list(range(200))))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = raw_input("what host are you connecting to?")
port = input("what port?\n")
s.connect((host,port))
print "connection successful."
time.sleep(5)
s.send("{},,{},,{},,{},,{},,{},,{},,{},,{},,{},,{},,{},,{}".format(0,0,name,backstory,role,5,5,5,5,10,player.attacks,player.locX,player.locY))
serial = s.recv(1024)
print "You're serial number is {}".format(serial)
while(s.recv(1024) != "ready"):
pass
break
except socket.error:
print "server is not running or is busy. please try again."
eventThread = thread.start_new_thread(eventHandler,(s,serial))
descisionThread = thread.start_new_thread(descisionHandler,(s,serial))
while 1:
pass
I did a bit of research and my best guess is that I need to use locks from the threading module, but I'm not sure. any suggestions?
Thanks in advance!
So the issue was the console input, as theSmallNothing said. There wasn't really a way around this limitation without serious hacking, so I proposed to improvise. My solution was to create a web app with python instead of using a console. There were a few advantages to this.
the server can handle multiple inputs at a time easily
things can happen while input is being entered(the solution to my problem)
no files need be downloaded for the user as everything can be accessed simply by entering the web address.
While not a perfect solution, sometimes finding an alternative is the next best thing.
Thanks all for your awesome help!

Python socket server/client not looping

I'm working on a number guessing game handled over two clients connected via socket, but for some reason after the initial loop it stops working and doesn't send/receive anything. The code all executes fine the first time around, but no matter what I change, the second time around I either get an error at the line guessNumber = int(s.recv(4096).decode() in the server file - where it reports an error trying to change '' into an int. This implies it's not receiving a value (in these instances, the Client program doesn't receive the "What is your guess? " string either).
The code below however just doesn't do anything after that initial loop, If you guess the number on that first loop then it works fine, your score is written to a file and they both end as they should.
But if you don't then it doesn't do anything either, so any help would be appreciated. It's running in Python 3.4.2 using the IDLE IDE.
Server:
import socket
import random
l = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
score = 0
guessNumber = 0
def within(value, goal, n):
numDifference = abs(value - goal)
if (numDifference <= n):
return True
else:
return False
scoreFile = open('scores', 'a')
randomNumber = random.randrange(0, 11)
l.bind(("127.0.0.1", 4001))
l.listen(5)
print("Waiting...")
while True:
(s,ca)=l.accept()
print("Connection from", ca)
while (not(within(guessNumber, randomNumber, 0))):
s.sendall("What is your guess? ".encode())
guessNumber = int(s.recv(4096).decode())
score += 1
print ("%d" % guessNumber)
if (within(guessNumber, randomNumber, 0)):
s.sendall(("You guessed correctly! \n Your score is %d" % score).encode())
scoreFile.write("Player %s has a score of %d \n" % (ca, score))
scoreFile.close()
s.sendall("1".encode())
elif (within(guessNumber, randomNumber, 3)):
s.sendall("You are getting close!".encode())
s.sendall("0".encode())
else:
s.sendall("You are way off".encode())
s.sendall("0".encode())
s.close()
Client:
import socket
gameOver = False
guessNumber = 0
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 4001))
while (gameOver != "1"):
#Send guess
guessNumber = input(s.recv(4096).decode())
s.sendall(guessNumber.encode())
#Recieve result
print(s.recv(4096).decode())
#Check whether game is over or not
gameOver = s.recv(4096).decode()
print ("Game Over")
s.close()
It turns out the client was closing it's socket after the first iteration because it ended with a receive. I've added some send confirmations after each receive to tell the Server it was performed successfully, and now all works as intended!

Categories