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!
Related
Repo is here: https://gitlab.com/andrzej_stopka/battleship/-/tree/client-server-communication
I make the battleship game in Python. It is working with sockets I'll show screen when I have problem.
Server.py/locate_ships()
def locate_ships(self, conn):
## It get inputs from a client to locate him ships
server_board = Board()
user_board = Board()
server_board.locate_server_ships()
for ship in user_board.ships:
while True:
arrangement = board_arrangement(user_board.board) # convert user board to message
conn.send(bytes(json.dumps(arrangement), encoding="utf-8"))
request = cord_request(ship.name, ship.occupied_spaces()) # convert ship info to message
conn.send(bytes(json.dumps(request), encoding="utf-8"))
cord = json.loads(conn.recv(1024)) # get user info
cord = cord["body"] # cords in message body
result = user_board.place_user_ship(ship, cord)
# insert cords to function to place ship on the board if input is valid
if ship == user_board.ships[-1]:
result = "Done"
server_acceptance = cord_answer(result) # convert to message if input is valid
conn.send(bytes(json.dumps(server_acceptance), encoding="utf-8"))
if result == "Placed": # if input is valid, go to the next ship
break
Client.py/main()
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
input("You are now connected to the Battleship server, press any key to continue")
s.send(bytes(game_invitation, encoding="UTF-8"))
acceptance = json.loads(s.recv(1024))
if acceptance["status"] == 0: # if status is equal 0 it means that server is ready to game
while True:
board_arrangement = json.loads(s.recv(1024))
print(board_arrangement)
show_board(board_arrangement["body"]) # print actual state of the board
cord_request = json.loads(s.recv(1024)) # it is request from server to give ship cords you want
cords = enter_cord(cord_request["message"]) # input
cords = json.dumps(ships_cords(cords[0], cords[1], cords[2])) # convert cords to a message
s.send(bytes(cords, encoding="utf-8"))
acceptance = json.loads(s.recv(1024)) # check if input was valid
if acceptance["message"] == "Done":
print("Locating is done")
break
else:
print(acceptance["message"])
continue
Problem is with last print - print(acceptance["message"]. If I put it in my code after first loop's run I get error - raise JSONDecodeError("Extra data", s, end)
json.decoder.JSONDecodeError: Extra data: line 1 column 560 (char 559) in board_arrangement = json.loads(s.recv(1024)) in second loop's run, it receives None object. Moreover if I put print() anywhere in server/locate_ships function the app is working well. It seems that after this print there is problem with communication between server and client but I don't know why and where. Is it possible that print() spoils communication?
Thanks in advance :)
I tried almost everything. I know that I could put empty print() on locate_ships in server.py but I don't want to do it and I want to get to know why the error appears.
I'm making a discord bot for my friends. This one feature, !status, is supposed to ping the server and report the replies.
from tcping import Ping
if message.content.startswith('!status'):
ping = Ping('HOST', 25565)
response = ping.ping(1)
await message.channel.send(str(response))
The problem is, the bot only responds with "None." Any help?
Im guessing you want to see if there is something available (as opposed to ping) ... if thats true this might work for you ...
import socket
def check(host,port,timeout=2):
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #presumably
sock.settimeout(timeout)
try:
sock.connect((host,port))
except:
return False
else:
sock.close()
return True
print(check('google.com',1234,timeout=1))
print(check('google.com',443,timeout=1))
maybe you want to time this... easy enough
import time
def timed_check(host,port,timeout=2):
t0 = time.time()
if check(host,port,timeout):
return time.time()-t0 # a bit inexact but close enough
print(timed_check('google.com',1234,timeout=1))
print(timed_check('google.com',443,timeout=1))
or maybe you want stats
def timed_stats_check(host,port,timeout=2,retries=5):
minimum,maximum,sumation = float('inf'),float('-inf'),0
errors = 0
for i in range(retries):
t = timed_check(host,port,timeout)
if t is None:
print("ERROR Unreachable...")
errors += 1
else:
print(f"Time {t:0.5f}s")
maximum = max(maximum,t)
minimum = min(minimum,t)
sumation += t
if retries > 0:
print(f"Max Time: {maximum:0.5f}s")
print(f"Min Time: {minimum:0.5f}s")
print(f"Average: {sumation/(retries-errors):0.2f}s")
print(f"Failures: {errors}/{retries}")
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!
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.