I have to write a small python program which implement client-server connection (TCP/IP) and play the Twenty Questions game. The server generates a random number between 1 and 100 and then multiple clients can make connection with it. The clients make its guess one by one and the server sent a feedback to them.
For example a client sends a struct ('<', 50) so its tipp is the number smaller than 50. The server receives the struct, checks if it's true or not and sends back a character ('I' - yes, 'N' - no, 'Y' - win, 'V' - lose, 'K' - lose in case of there's at least another client still playing the game). The clients make it's tipps based on binary search. I didn't handle yet those cases when the correct number is the range that client tipps, but now not this is why I'm asking for help.
How can I make the server handle multiple clients? At now, if a client connects to the server, it plays the entire game and not waiting for other clients to connect.
server.py:
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
import select
import struct
import random
server_addr = ('', 10000)
unpacker = struct.Struct('c I')
correct_num = random.randint(1, 100)
answer = ''
print('Correct number:', correct_num)
with socket(AF_INET, SOCK_STREAM) as server:
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server.bind(server_addr)
server.listen(5)
sockets = [server]
while True:
readables, writables, exceptionals = select.select(sockets, sockets, sockets, 1)
if not (readables or writables or exceptionals):
continue
for s in readables:
if s is server: # new client connect
client_conn, client_addr = s.accept()
client_conn.setblocking(0)
print('Connected:', client_addr)
sockets.append(client_conn)
else: # handle client
data = s.recv(unpacker.size)
if not data:
sockets.remove(s)
s.close()
print('Exited')
else:
print('Received:', data)
unp_data = unpacker.unpack(data)
print('Unpack:', unp_data)
if answer == 'Y':
answer = 'V'
else:
if unp_data[0].decode() == '=':
if int(unp_data[1]) == correct_num:
answer = 'Y'
else:
answer = 'K'
elif unp_data[0].decode() == '>':
if correct_num > int(unp_data[1]):
answer = 'I'
else:
answer = 'N'
elif unp_data[0].decode() == '<':
if correct_num < int(unp_data[1]):
answer = 'I'
else:
answer = 'N'
print('Evaluated and sent back', answer)
s.sendall(str(answer).encode())
client.py:
from socket import socket, AF_INET, SOCK_STREAM
import struct
import random
server_addr = ('localhost', 10000)
packer = struct.Struct('c I')
operators = ['<', '>', '=']
last_num = last_n_num = last_i_num = 0
last_op = last_n_op = last_i_op = ''
with socket(AF_INET, SOCK_STREAM) as client:
client.connect(server_addr)
lowest_num = 1
highest_num = 100
mid = lowest_num + (highest_num - lowest_num) // 2
sent_op = operators[mid % (len(operators) - 1)]
range_nums = [mid]
packed_data = packer.pack(sent_op.encode(), int(mid))
print('Client make starting guess')
client.sendall(packed_data)
while True:
data = client.recv(1).decode()
if data == 'V':
print('Someone else won\nClient exits')
client.close()
exit(0)
elif data == 'Y':
print('Client won')
client.close()
exit(0)
elif data == 'K':
print('Client lose')
client.close()
exit(0)
else:
if data == 'I':
if sent_op == '<':
highest_num = mid - 1
elif sent_op == '>':
lowest_num = mid + 1
if data == 'N':
if sent_op == '<':
lowest_num = mid + 1
elif sent_op == '>':
highest_num = mid - 1
mid = lowest_num + (highest_num - lowest_num) // 2
if mid in range_nums:
sent_op = '='
else:
range_nums.append(mid)
if lowest_num >= highest_num:
sent_op = '='
else:
sent_op = operators[mid % (len(operators) - 1)]
print('Client make another guess')
packed_data = packer.pack(sent_op.encode(), int(mid))
client.sendall(packed_data)