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!
Related
How can I create a socket server that allows connections from other networks?
Currently, my server is running on my IPv4 address. This works fine. However, the server cannot be connected to from other networks. I know you can do port forwarding to get this to work, but how can I make the script automatically do port forwarding?
Here is my server code:
import socket, pickle
from _thread import *
from serverside import Player, get_chest_tiles
from maps import maps
server = '10.0.0.187'
port = 5555
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((server, port))
except socket.error as e:
print(e)
s.listen()
print(f'Server started with address: {server}, on port: {port}\nWaiting for connections...')
players = []
zombies = [False]
current_map = maps['town']
chest_tiles = get_chest_tiles(current_map[0])
def threaded_client(conn, player):
players.append(Player())
conn.sendall(pickle.dumps([players[player], player]))
while True:
reply = []
players_reply = []
try:
data = pickle.loads(conn.recv(999999))
if type(data) == list:
if data[0] == 'UPDATE_ZOMBIES':
global zombies
zombies = data[1]
elif data[0] == 'UPDATE_MAP':
global current_map
current_map = data[1]
else:
players[player] = data
if not data:
break
else:
for p in range(len(players)):
if p < player or p > player:
players_reply.append(players[p])
reply = [players_reply, current_map, zombies, chest_tiles]
conn.sendall(pickle.dumps(reply))
except:
break
print('Lost connection')
players.pop(player)
conn.close()
currentPlayer = 0
while True:
conn, addr = s.accept()
print('Connected to:', addr)
start_new_thread(threaded_client, (conn, currentPlayer))
currentPlayer += 1
I was following a tutorial and got stuck here. When I ran the same code for the first time, It went well. But from the second time, it shows error in the same code. I restarted my computer and then it ran once and from the second time, it again shows error.
#THE CODE:
import socket
from _thread import *
import sys
server = "192.168.0.102"
port = 5555
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((server, port))
except socket.error as e:
str(e)
s.listen(2)
print("Waiting for a connection , Server Started")
def read_pos(str):
str = str.split(",")
return int(str[0]), int(str[1])
def make_pos(tup):
return str(tup[0]) + "," + str(tup[1])
pos = [(0, 0), (100, 100)]
def threaded_client(conn, player):
conn.send(str.encode(make_pos(pos[player])))
reply = ""
while True:
try:
data = read_pos(conn.recv(2048).decode())
pos[player] = data
if not data:
print("Disconnected")
break
else:
if player == 1:
reply = pos[0]
else:
reply = pos[1]
print("Received : ", data)
print("Sending: ", reply)
conn.sendall(str.encode(make_pos(reply)))
except:
break
print("Lost Connection")
conn.close()
currentPlayer = 0
while True:
conn, addr = s.accept()
print("Connected to : ", addr)
start_new_thread(threaded_client, (conn, currentPlayer))
currentPlayer += 1
Try using a different IP address. The code worked correctly when I used 127.0.0.1 which is the local machine.
server = "127.0.0.1"
port = 5555
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
Im trying to make a simple game but cant understand how to make it work and send more then one thing over the network. It works the first time but it supposed to go 10 times. It only sends 1 random number now but i want it to send one new when the game goes again and want a new number.
Server
import socket, random
sock = socket.socket()
host = socket.gethostname()
port = 12345
sock.bind((host, port))
sock.listen(5)
c, addr = sock.accept()
cpu = random.choice(range(0, 3))
c.send(cpu)
gameon = c.recv(int(1024))
Client
import socket, random
sock = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 12345 # Reserve a port for your service.
sock.connect((host, port))
GAMEON = 'Rock', 'Paper', 'Scissors'
game = 0
iwin = 0
ilose = 0
tie = 0
while game < 10:
for i in range(0, 3):
print "%d %s" % (i + 1, GAMEON[i])
player = int(input ("Choose from 1-3: ")) - 1
cpu = int(sock.recv(1024))
print cpu
print""
print "%s vs %s" % (GAMEON[player], GAMEON[cpu])
print ""
if cpu != player:
if (player - cpu) % 3 < (cpu - player) % 3:
print "Player wins\n"
iwin += 1
else:
print "CPU wins\n"
ilose += 1
else:
print "TIE!\n"
tie += 1
game += 1
sock.send(str(game))
print"Game is done"
print"you win: ", (iwin), "Times"
print"computer wins: ", (ilose), "Times"
print"tie: ", (tie), "Times"
The problem is that your server will serve one request and then stop. You need to put it in some kind of while loop.
I wrote a basic IM server/client in Python which might help you: https://github.com/hdgarrood/PyMess/blob/master/server/basictcpserver.py#L59
You need threads to do your bidding.
Example code
# Listen
s.listen(10)
print 'Socket now listening on port ' + str(PORT) + "..."
while 1:
# wait
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ":" + str(addr[1])
# Let's fork a thread for each request
processThread = threading.Thread(target=processConnection, args=(conn, addr[0]));
processThread.start()
s.close()
Your processConnection will look like this:
# Process Connection
def processConnection(conn, ip):
print "Thread started..."
print "-------------------------------------------------------------";
cpu = random.choice(range(0, 3))
conn.send(cpu)
gameon = conn.recv(int(1024))
conn.close()
Update 1
If you need the server to keep talking with the client, then do this. Server will wait for the client to send back a message. If client sends anything, server will return a random number. If the client doesn't need anymore data, just close the connection and server loop will end.
import socket, random
sock = socket.socket()
host = socket.gethostname()
port = 12345
sock.bind((host, port))
sock.listen(5)
c, addr = sock.accept()
white True:
cpu = random.choice(range(0, 3))
c.send(cpu)
gameon = c.recv(int(1024))
if gameon is None:
break
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.