Socket issue when using threads - python
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!
Related
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'.
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!
python multithreaded sniffer- exit from thread
I have created a packet sniffer in python using scapy but kind of stuck in the multithreaded stuff.. def sniffer(ip): filter_str = "icmp and host " + ip packets=sniff(filter=filter_str,count=20) status= False for p in packets: packet_load=str(p['Raw'].load) if packet_load.find("##")!= -1: status=True log_thread = Thread(target=logger,args=(packets,)) log_thread.start() log_thread.join() break if status==True: print "Suspicious Packets sniffed!!" user_ip = raw_input("Do you want to continue sniffing???(y/n)") while 1: if user_ip=="y" or user_ip=="Y": new_thread = Thread(target=sniffer, args=(ip,)) new_thread.start() new_thread.join() else: #need somthing to quit the program return Here, my sniffer sniffs 20 packets at a time and waits for user input for further sniffing. However if the user enters 'n' as input, then the program hangs. Ideally I would want the program to quit if the user enters 'n'. Can I know what I'm doing wrong here??
while 1 is rarely a good choice when writing a finite loop. Try using flags instead: leaving = False while not leaving: user_ip = raw_input("Do you want to continue sniffing???(y/n)") if user_ip.lower() == 'y': new_thread = Thread(target=sniffer, args=(ip,)) new_thread.start() new_thread.join() elif user_ip.lower() == 'n': print "Leaving sniffer" leaving = True return
Python network/socket programming, simple game
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
Python can't communicate with subprocess of a Minecraft server
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.