My target is print the message from function result
on the client's screen. But only ONE client can received the message
I think the problem is about the socket.recv, but I have no idea how to handle it.
The client.py is here
#!/usr/bin/python3
# ********************************************************* #
#
# Function: Authentication
# get user input
# pass to server to check that the input is valid or not.
#
# ********************************************************* #
def Authentication(clientSocket):
user_name = input("Please input your user name: ")
password = input("Please input your password: ")
username_with_password = str("/login " user_name " " password)
clientSocket.send(username_with_password.encode())
back_msg = clientSocket.recv(1024).decode()
print(back_msg)
if(back_msg == "1001 Authentication successful"):
clientSocket.send("Yes".encode())
return True
else:
clientSocket.send("NO".encode())
return False
# ********************************************************* #
#
# Function: List_request
# call when user input /list
# print the room list
#
# ********************************************************* #
def List_request(clientSocket):
clientSocket.send("list".encode())
back_msg = pickle.loads(clientSocket.recv(1024))
for i in back_msg:
print(i, end=' ')
print("")
# ********************************************************* #
#
# Function: exit_request
# call when user input /exit
# print the exit message
#
# ********************************************************* #
def exit_request(clientSocket):
clientSocket.send("exit".encode())
back_msg = clientSocket.recv(1024).decode()
print(back_msg)
# ********************************************************* #
#
# Function: enter_request
# call when user input /enter
# first split /enter and x, where x is the room number
#
# ********************************************************* #
def enter_request(clientSocket, num):
willsend = "enter " str(num)
clientSocket.send(willsend.encode())
back_msg_1 = clientSocket.recv(1024).decode()
print(back_msg_1)
if(back_msg_1 == '3011 Wait'):
back_msg_2 = clientSocket.recv(1024).decode()
print(back_msg_2)
return 'wait2'
elif(back_msg_1 == "3012 Game started. Please guess true or false"):
return 'wait'
else:
return '2'
# ********************************************************* #
#
# Function: OtherMsg
# call when user invalid input
#
# ********************************************************* #
def OtherMsg(clientSocket):
msg = "other"
clientSocket.send(msg.encode())
msg_back = clientSocket.recv(1024).decode()
print(msg_back)
# ********************************************************* #
#
# Function: GrabCommand_Game_Hall
# Call when user go into game hall
# handle different command by different function
#
# ********************************************************* #
def GrabCommand_Game_Hall(command, num, clientSocket):
if(command == "/list"):
List_request(clientSocket)
elif(command == "/exit"):
exit_request(clientSocket)
return '1'
elif(command == "/enter"):
c = enter_request(clientSocket, num)
return str(c)
else:
OtherMsg(clientSocket)
return '2'
# ********************************************************* #
#
# Function: PlayGame
# call when user in the game
# split the /guess true_false command to true / false
# determine the input is valid or invalid
#
# ********************************************************* #
def PlayGame(clientSocket, msg):
invalid = "NO!"
if ("/guess " in msg):
msg1 = msg.split(" ")[1]
if msg1 == "true" or msg1 == "false":
clientSocket.send(msg1.encode())
print(clientSocket.recv(2048).decode())
return '1'
else:
clientSocket.send(invalid.encode())
print(clientSocket.recv(1024).decode())
return '2'
elif msg == "":
return '2'
else:
clientSocket.send(invalid.encode())
print(clientSocket.recv(1024).decode())
return '2'
def main(argv):
serverName = str(sys.argv[1])
serverPort = int(sys.argv[2])
try:
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSocket.connect((serverName, serverPort))
except socket.error as err:
print("Socket error: ", err)
sys.exit(1)
# Authentication until successes
while( Authentication(clientSocket) != True):
{}
Input = ""
num = 0
# In the game hall, only leave when user input /exit.
while(Input != '/exit' ):
Input = input()
if(" " in Input): # used to split /enter command
Input, num = Input.split(" ")[0], Input.split(" ")[1]
var = GrabCommand_Game_Hall(Input, num, clientSocket)
if(var == '1'): # terminae
Input = '/exit'
elif(var == '2'):
{}
elif (var == 'wait'): # the "3001" command printed, wait for other player
msg = ""
while (PlayGame(clientSocket, msg) != '1'):
msg = input()
elif (var == 'wait2'): # the "3002 command printed, go to play game.
msg = ""
while (PlayGame(clientSocket, msg) != '1'):
msg = input()
else:
{}
print("Client ends")
clientSocket.close()
exit(1)
if __name__ == '__main__':
main(sys.argv)
The server.py is there
# ********************************************************* #
#
# Function: ReadUserInfo
# Read and split the username and password from UserInfo.txt
# store the username and password in the list
#
# ********************************************************* #
def ReadUserInfo(filepath,username, password):
with open(str(filepath)) as f:
lines = f.readlines()
for line in lines:
username.append((str(line).split(':')[0]))
password.append(str(line).split(':')[1].rstrip('\n'))
# ********************************************************* #
#
# Function: authenticates
# Check whether username, password is correct or not.
#
# ********************************************************* #
def authenticates(username, password, username_list, password_list):
if username in username_list:
if password in password_list:
if username_list.index(str(username)) != password_list.index(str(password)):
return "1002 Authentication failed"
else:
return "1001 Authentication successful"
else:
return "1002 Authentication failed"
else:
return "1002 Authentication failed"
# ********************************************************* #
#
# Initialize the variable
#
# ********************************************************* #
NUM_OF_ROOM = 10
serverPort = int(sys.argv[1])
UserInfo_path = str(sys.argv[2])
username = [] #store all username
password = [] #store all password
addr_l = [] #store all address
name_list = []
current_rm_num = []
guess_box = []
guess = bool(random.randint(0, 1))
room = [NUM_OF_ROOM] [0] * 10 #There 10 rooms
room[0] = NUM_OF_ROOM #the first element of room list is 10 (num of room).
print(room)
ReadUserInfo(UserInfo_path, username, password)
state = [0] * len(username)
# ********************************************************* #
#
# Function: RecevFromClient
# get client message (input)
# use for auth. users
# Check the input is valid or not
#
# ********************************************************* #
def RecvFromClient(connectionSocket):
message1 = connectionSocket.recv(2048).decode()
name_list.append(str(message1).split(" ")[1])
msg_return = authenticates(str(message1).split(" ")[1], str(message1).split(" ")[2], username, password)
connectionSocket.send(msg_return.encode())
message = connectionSocket.recv(2048).decode()
if message == 'Yes':
state[username.index(str(message1).split(" ")[1])] =1
return str(message)
# ********************************************************* #
#
# GameHallMsg
# Receive command in game hall
#
# ********************************************************* #
def GameHallMsg(connectionSocket, addr, addr_l):
message1 = connectionSocket.recv(1024).decode()
if(message1 == 'list'):
room_1 = ["3001"] room
data = pickle.dumps(room_1)
connectionSocket.send(data)
return 'ok'
elif(message1 == 'exit'):
rtn_msg = "4001 Bye bye"
connectionSocket.send(rtn_msg.encode())
state[addr_l.index(addr)-1] -= 1
return 'bye'
elif(message1.split(" ")[0] == 'enter'):
num = int(message1.split(" ")[1])
if(num > len(room)-1 or num == 0):
msg = "Please input the /enter command again! "
connectionSocket.send(msg.encode())
return 'ok'
elif (room[num] == 0):
rtn_msg_1 = "3011 Wait"
room[int(num)] = 1
state[addr_l.index(addr)] = int(num)
current_rm_num.append(num)
print("Player name:",name_list[addr_l.index(addr)],"joined room", num)
connectionSocket.send(rtn_msg_1.encode())
return 'wait'
elif (room[int(num)] == 1):
room[int(num)] = 1
state[addr_l.index(addr)] = 1
rtn_msg_2 = "3012 Game started. Please guess true or false"
current_rm_num.append(num)
print("Player name:", name_list[addr_l.index(addr)], "joined room", num)
connectionSocket.send(rtn_msg_2.encode())
return 'jump'
elif (room[int(num)] >= 2):
rtn_msg_3 = "3013 The room is full"
connectionSocket.send(rtn_msg_3.encode())
return 'ok'
else:
return 'NO'
# ********************************************************* #
#
# Function: result
# check the result.. i.e. win / lose / tie
#
# ********************************************************* #
def result(connectionSocket, guess_box, addr, addr_l):
a = 0
c = addr[1]
print(addr)
print(addr_l)
if(guess_box[0] == guess_box[1]):
msg = "Tie!!"
connectionSocket.sendto(msg.encode(), addr)
return '2'
elif(guess_box[addr_l.index(c)] == guess):
msg1 = "You are Winner!"
a =1
connectionSocket.sendto(msg1.encode(), addr)
return '2'
elif(guess_box[addr_l.index(c)] != guess):
msg2 = "You lose the game."
a =1
connectionSocket.sendto(msg2.encode(), addr)
return '2'
# ********************************************************* #
#
# Function: TF
# convert the /guess true or /guess false --> true or false
#
# ********************************************************* #
def TF(connectionSocket, var, guess_box):
msg = connectionSocket.recv(1024).decode()
print("recv:",msg)
if(msg == 'true'):
msg = 'True'
var = str(var)
msg = bool(msg == var)
guess_box.append(msg)
return 'ok'
elif(msg == 'false'):
msg = 'False'
var = str(var)
msg = bool(msg == var)
guess_box.append(msg)
return 'ok'
else:
print(msg)
statement = "4002 Unrecognized message!!"
connectionSocket.send(statement.encode())
return 'again'
# ********************************************************* #
#
# Thread
# for every client
#
# ********************************************************* #
class ServerThread(threading.Thread):
def __init__(self, client):
threading.Thread.__init__(self)
self.client = client
def run(self):
connectionSocket, addr = self.client
addr_l.append(addr[1])
while(RecvFromClient(connectionSocket) == "NO"):
{}
print(addr_l)
a = ''
while(a != 'ex'):
var = GameHallMsg(connectionSocket, addr[1], addr_l)
if var == 'bye':
break
elif (var == 'wait'):
while(a != 'b' ):
if(len(current_rm_num) == 2):
rtn_msg_2 = "3012 Game started. Please guess true or false"
connectionSocket.send(rtn_msg_2.encode())
print("guess is:", guess)
while (len(guess_box) != 2):
print(guess_box)
TF(connectionSocket, guess, guess_box)
a = 'b'
result(connectionSocket, guess_box, addr, addr_l)
elif (var == 'NO'):
rtn_msg_4 = "4002 Unrecognized message"
connectionSocket.send(rtn_msg_4.encode())
elif(var == 'ok'):
{}
elif(var == 'jump'):
while (a != 'b'):
if (len(current_rm_num) == 2):
while (len(guess_box) != 2):
print(guess_box)
TF(connectionSocket, guess, guess_box)
result(connectionSocket, guess_box, addr, addr_l)
a = 'b'
class ServerMain:
def server_run(self):
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
serverSocket.bind(("localhost", serverPort))
except socket.error as err:
print("Binding error: ", err)
sys.exit(1)
serverSocket.listen(len(username))
while True:
client = serverSocket.accept()
t = ServerThread(client)
t.start()
if __name__ == '__main__':
server = ServerMain()
server.server_run()
The content of UserInfo.txt is username and password with format Username:password
The expected input - output are:
For Server's terminal
% python3 server.py 12345 [path_of_userinfo.txt]
For Client_1's terminal (input starts with "*")
% python3 client.py localhost 12345
Please input your user name:*username
Please input your password:* password
1001 Authentication successful
*/enter room_num
3011 Wait
3012 Game started. Please guess true or false
*/guess true
You are the loser! # If the random variable is false, not equal to true
For Client_2's terminal (input starts with "*")
% python3 client.py localhost 12345
Please input your user name: *username_2
Please input your password: *password_2
1001 Authentication successful
*/enter room_num
3012 Game started. Please guess true or false
*/guess false
You are winner! # If the random variable is false
CodePudding user response:
Regarding only the one problem you address:
print the message from function result on the client's screen. But only ONE client can received the message
The problem comes from the use of a different thread for each client. The thread which receives a guess as first stays in its
while (len(guess_box) != 2):
print(guess_box)
TF(connectionSocket, guess, guess_box)
loop and waits for another message, which doesn't come. The thread which receives a guess as second sends the result to its own client only.
I don't think there's a sensible way to fix this while keeping this dthreaded approach.
Can I change the structure of my code by using those functions I implemented?
Here's a substitute for the while True
loop in server_run
that doesn't require changes in those functions other than server_run
.
from select import select
connections = []
room_connection = {}
for reads in iter(lambda: select([serverSocket] connections, [], [])[0], []):
for ready in reads: # for each socket which select reports is readable
if ready == serverSocket: # it's the server socket, accept new client
connectionSocket, addr = serverSocket.accept()
connections.append(connectionSocket)# store the connection socket
while RecvFromClient(connectionSocket) == "NO": pass
else: # message (or disconnect) from a client
try: var = GameHallMsg(ready, ready, connections)
except socket.error: var = 'bye'
if var == 'bye': # client finished, remove from list
connections.remove(ready)
ready.close()
elif var == 'wait': # store first player's connection
room_connection[current_rm_num.pop()] = ready
elif var == 'NO':
rtn_msg_4 = "4002 Unrecognized message"
ready.send(rtn_msg_4.encode())
elif var == 'jump':
readyroom = current_rm_num.pop()
# find and notify other player in the room
other = room_connection.pop(readyroom)
rtn_msg_2 = "3012 Game started. Please guess true or false"
other.send(rtn_msg_2.encode())
print("guess is:", guess)
# query and inform both players
guess_box = []
while TF(ready, True, guess_box) != 'ok': pass
while TF(other, True, guess_box) != 'ok': pass
result(ready, guess_box, ('', 0), [0])
result(other, guess_box, ('', 1), [0, 1])
room[readyroom] = 0