I'm writing an Encrypted R-P-S (Rock, Paper, Scissors) Game with Python, and it works like this. The server is leading the game, and the two clients is just sending their choice to the server.
First, the server is waiting for 2 players to join, when 2 players have joined, he is starting the game and letting both of the clients to choice an option.
My problem is that when the first client connects, and then the another, the first client automatically disconnects.
So, I don't know how to handle both of the clients, and let the first client choose an option and then let the second choose option.
*Note: I'm using the same client file for both of the clients.
Server:
import socket
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from time import sleep
def rules(first_choice, second_choice, mem1, mem2) -> str:
if (first_choice == 'R' and second_choice == 'P'
or first_choice == 'P' and second_choice == 'S'
or first_choice == 'S' and second_choice == 'R'):
return f'Result: Player 2 Won\nPlayer 1 Choice - {first_choice}\nPlayer 2 Choice - {second_choice}'
else:
return f'Result: Player 1 Won!\nPlayer 1 Choice - {first_choice}\nPlayer 2 Choice - {second_choice}'
class Connect:
def __init__(self):
players = 0
self.prikey = RSA.generate(1024)
self.pubkey = self.prikey.publickey()
self.token = PKCS1_OAEP.new(self.prikey)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(('0.0.0.0', 21523))
sock.listen(2)
print('Waiting for at least 2 players, please wait.')
while True:
self.conn, self.addr = sock.accept()
players += 1
if players == 1:
print(f'Player 1 is {self.addr}')
self.player1 = self.addr
elif players == 2:
print(f'Player 2 is {self.addr}')
self.player2 = self.addr
self.connection()
def connection(self) -> None:
print('2 Players have joined, starting game in 5 seconds.\n')
sleep(5)
self.conn.send('Y'.encode())
self.game_play()
def game_play(self) -> None:
self.conn.send(self.pubkey.exportKey())
choice_1_cipher = self.conn.recv(1024)
choice_1_plain = self.token.decrypt(choice_1_cipher)
print('Got first choice, waiting for another choice..')
choice_2_cipher = self.conn.recv(1024)
choice_2_plain = self.token.decrypt(choice_2_cipher)
print('Got second answer, calculating winner!')
print(rules(choice_1_plain, choice_2_plain, self.player1, self.player2))
if __name__ == '__main__':
Connect()
Client:
import socket
import random
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
class Client:
def __init__(self):
self.prikey = RSA.generate(2048)
self.pubkey = self.prikey.publickey()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect(('10.0.0.42', 21523))
data = self.sock.recv(1024).decode()
if data == 'Y':
self.start_game()
def start_game(self) -> None:
print('\n [R]ock | [P]aper | [S]cissors - ')
while True:
my_choice = input().upper()
if my_choice not in ['R', 'P', 'S']:
print('Invalid Input, input must be one of those R\\P\\S')
else:
user_pubkey = RSA.importKey(self.sock.recv(2048))
token = PKCS1_OAEP.new(user_pubkey)
cipher_choice = token.encrypt(my_choice.encode())
self.sock.send(cipher_choice)
if __name__ == '__main__':
try:
Client()
except Exception as e:
print(f'err: {e}')
except KeyboardInterrupt:
print('A player has pressed [Ctrl + C] to quit the game, game ended!')
self.conn in self.conn, self.addr = sock.accept() when the 2 client connects gets overwritten and the self.conn of the player1 is lost.
I guess you should assign the self.conn to self.player1_conn before returning to the beginning of the while loop waiting for the 2 player.
This is actually a recurrent problem in your script because when you say self.conn.send('Y'.encode()) self.conn is referring only to the second player connection (which i guess it's not what you intend to do).
You should separate the conn in player1_conn and player2_conn and then you'll be able to chose to which player send what you need.
Related
the issue with my program is as follows:
i've been working on a socket server for some rp stuff dont mind that part, the more worrisome part is the fact that now my client just closes after trying to fix a massive vulnerability where if you press enter it will show "invalid input" then press enter again it will just log you into the server itself via a prompt shown after login. that part isnt relevant only the fact that the client closes immediately when i open it, any advice or issues i should look at? you should also note that def passwd(): was added in attempt to fix the issue, what i did was put the password prompt in a function, then call the function after connecting via ngrok tunnel, the code is below:
import socket
from os import name as os_name, system
from colorama import init, Fore as cc
import select
import time
dr = DR = r = R = cc.LIGHTRED_EX
g = G = cc.LIGHTGREEN_EX
b = B = cc.LIGHTBLUE_EX
m = M = cc.LIGHTMAGENTA_EX
c = C = cc.LIGHTCYAN_EX
y = Y = cc.LIGHTYELLOW_EX
w = W = cc.RESET
HEADER = 64
clear = lambda: system('cls') if os_name == 'nt' else system('clear')
clear()
PORT = input("Enter Port Number > ")
FORMAT = "utf-8"
DISCONNECT_MESSAGE = "!disconnect"
SERVER = input("Enter Tunnel Address > ")
PORT1 = int(PORT)
ADDR = (SERVER, PORT1)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ADDR)
passwd()
def send(msg):
message = msg.encode(FORMAT)
msg_length = len(message)
send_length = str(msg_length).encode(FORMAT)
send_length += b' ' * (HEADER - len(send_length))
client.send(send_length)
client.send(message)
print(client.recv(2048).decode(FORMAT))
clear()
def ssrselec():
ssr = input("Input User ID > ")
if ssr:
clear()
send(ssr)
time.sleep(2)
if not ssr:
clear()
print("INVALID INPUT")
client.close()
def select():
selec = input("Types: Internal, External\n\nSelect Database Type > ")
if selec:
clear()
send(selec)
time.sleep(2)
ssrselec()
if not selec:
clear()
print("INVALID INPUT")
client.close()
print("To disconnect type !disconnect\n")
def passwd():
inp = input("Input Database Password > ")
if inp:
clear()
send(inp)
time.sleep(2)
select()
if not inp:
clear()
print("INVALID INPUT")
client.close()
inp2 = input(" > ")
if inp2:
clear()
send(inp2)
time.sleep(2)
select()
if not inp2:
clear()
print("INVALID INPUT")
client.close()
clear()
select()
clear()
my linter shows that passwd() is called before it is declared.
You should define passwd() before it is called.
You can do this by defining it earlier in the code or by hoisting all functions with this at the end:
if __name__==`__main__`:
# some code
I am making an online flag guessing game using sockets.
Server's code below (sorry for pasting the entire code, I've been testing and have literally no idea what the problem could be):
import socket
import threading
import random
from time import sleep
from func import get_flags
flags = get_flags()
flag_names = [i for i in flags]
current_flag = " "
show_answer = False
errorCounter = 0
HEADER = 64
PORT = 5050
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
players = []
num_of_players = int(input("Number of players: "))
def handle_client(conn, addr):
global show_answer, current_flag
print(f"[NEW CONNECTION] {addr} connected.")
connected = True
player = ()
while connected:
print(current_flag)
msg_length = conn.recv(HEADER).decode(FORMAT)
if msg_length:
msg_length = int(msg_length)
msg = conn.recv(msg_length).decode(FORMAT)
#print(f"[{addr}] {msg}")
msg = msg.lower()
msg = msg.split(" ")
try:
if msg[0] == "!set_username" and len(msg) > 1:
player = (msg[1], addr)
players.append(player)
elif msg[0] == "!get_flags":
conn.send(str(flags).encode(FORMAT))
elif msg[0] == "!ready":
conn.send(str(len(players) >= num_of_players).encode(FORMAT))
elif msg[0] == "!get_current_flag":
conn.send(current_flag.encode(FORMAT))
elif msg[0] == "!show_answer":
conn.send(str(show_answer).encode(FORMAT))
except Exception:
print("asd")
#conn.send("Msg received".encode(FORMAT))
players.remove(player)
conn.close()
def start():
global show_answer, current_flag
server.listen()
print(f"[LISTENING] Server is listening on {SERVER}:{PORT}")
while len(players) < num_of_players:
conn, addr = server.accept()
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
print("\nThe game has started.\n")
while True:
sleep(3)
show_answer = False
current_flag = random.choice(flag_names)
sleep(10)
show_answer = True
if __name__ == "__main__":
print("[STARTING] server is starting...")
start()
My problem is:
When I call the start() function, and the lobby fills up, the "game clock" starts, which determines how much time the players have to guess the flag, and the time in which they can see the correct answer. When I change these variables (show_answer and current_flag), they change, but not in in handle_client(). Why is that?
The client is able to connect just fine, but can't see the updated variables.
I am using Python 3.9.5 if that helps.
I have coded a drawing & guessing game simular to skribble.io and I'm using a TCP Socketserver for providing the game information to all connected players. On the client side is a thread running with a while true loop which is constently requesting for the needed information and on the server side is running a while true loop which is receiving the request and giving the right response for that. For serialization of the data I use pickle. When I'm testing my game on my local machine with a running server and some clients everything is working fine but If I'm testing it on my local network or over the internet it's starting to get very laggy on the client side and everything takes a huge amount of time to display the right server information for example a timer which is running in my game isn't updating every second and also the drawing is laggy.
Client Side:
def receive_data():
global connected_clients, client, start, grid, in_game, lobby_id
while True:
try:
if not in_game:
data = network.receive()
if isinstance(data, list): # get connected clients
connected_clients = data
for c in connected_clients: # get current client
if c.uid == client.uid:
client = c
elif data == 'start':
start = True
in_game = True
else:
if not client.drawing:
res = network.get('grid')['grid'] # get grid
grid.update(res)
# get round information
topbar.word = network.get('word')['word'] # get word
client.drawing = network.get('drawing')['drawing']
topbar.time = network.get('time')['time'] # get round time
topbar.round = network.get('round')['round']
response = network.get('clients') # get all connected clients
connected_clients = response['clients']
for c in connected_clients: # get current client
if c.uid == client.uid:
client = c
messages = network.get('chat')['chat'] # get chat
chat.update(messages, client)
except:
pass
Network method get():
def get(self, data): # returns the response for the request
try:
self.client.send(pickle.dumps(data))
buff_size = 4096
data = bytearray()
while True:
chunk = self.client.recv(buff_size)
data += chunk
if len(chunk) < buff_size:
break
return pickle.loads(data)
except Exception as e:
print(e)
Server Side:
def handle_player(self, connection, player):
data = None
send_msg = {}
while True:
try:
try:
data = self.receive(connection)
except:
pass
if not self.in_game: # lobby logic
if data == 'ready':
player.ready = True
self.broadcast(self.players_to_clients())
if self.all_players_ready():
self.broadcast('start')
self.game = Game(self.players)
for p in self.players:
p.set_game(self.game)
self.in_game = True
elif self.in_game: # in game logic
if player.game:
if isinstance(data, list):
player.game.grid.completely_update(data)
elif isinstance(data, dict):
player.game.make_player_guess(player, data['guess'])
if data == 'word':
send_msg['word'] = player.game.round.word
elif data == 'drawing':
player.drawing = player.game.round.player_drawing == player
if player.drawing:
send_msg['drawing'] = True
else:
send_msg['drawing'] = False
elif data == 'clients':
send_msg['clients'] = self.players_to_clients()
elif data == 'time':
send_msg['time'] = player.game.round.draw_time
elif data == 'grid':
send_msg['grid'] = player.game.grid.get_grid()
elif data == 'chat':
send_msg['chat'] = player.game.chat.messages
elif data == 'round':
send_msg['round'] = player.game.round_count
connection.send(pickle.dumps(send_msg))
else:
pass
except socket.error:
print(f'{player.name} disconnected.')
player.game.player_disconnect(player)
if player in self.players:
self.players.remove(player)
if connection in self.connections:
self.connections.remove(connection)
self.broadcast(self.players_to_clients())
break
I got already an idea for a possible solution which is to switch from TCP to UDP and TCP but i don't know how to implement both in a way that I can send all necessary information.
PS: Sorry for any english mistakes and thanks for any help.
I am creating a simple chat room server using python and when I send data using I'm not receiving it. The code worked until I sepperated it using functions and classes. I did this so it would be simpler to add a UI
here's my server side code:
import socket
import select
from tkinter import *
import threading
HEADER_LENGTH = 10
IP = socket.gethostbyname('0.0.0.0')
PORT = 1234
class ServerNoGui():
def __init__(self):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_socket.bind((IP, PORT))
self.server_socket.listen()
self.sockets_list = [self.server_socket]
self.clients = {}
print("server started")
print("Starting thread sub-proccesses...")
acceptLoop = threading.Thread(target=self.acceptUsers)
acceptLoop.start()
recieveLoop = threading.Thread(target=self.manageDataSending)
recieveLoop.start()
print("sub-proccesses started!")
def recieve_message(self, client_socket):
message_header = client_socket.recv(HEADER_LENGTH)
if not len(message_header):
return False
message_length = int(float(message_header.decode('utf-8').strip()))
return {'header': message_header, 'data': client_socket.recv(message_length)}
def acceptUsers(self):
read_sockets, _x_, exception_sockets = select.select(self.sockets_list, [], self.sockets_list)
for notified_socket in read_sockets:
if notified_socket == self.server_socket:
client_socket, client_address = self.server_socket.accept()
print("accepted")
user = self.recieve_message(client_socket)
#print(user)
print("Recieved")
if(not user):
continue
self.sockets_list.append(client_socket)
print("added to list")
self.clients[client_socket] = user
print("created user")
print(f"Accepted connection from {client_address[0]}{client_address[1]} username: {user['data'].decode('utf-8')}")
def manageDataSending(self):
while True:
read_sockets, _x_, exception_sockets = select.select(self.sockets_list, [], self.sockets_list)
print("point")
for notified_socket in read_sockets:
if notified_socket == self.server_socket:
print("point 0")
self.acceptUsers()
else:
print("point 1")
message = self.recieve_message(notified_socket)
if(message is False):
print(f"Closed connection from {self.clients[notified_socket]['data'].decode('utf-8')}")
self.sockets_list.remove(notified_socket)
del self.clients[notified_socket]
continue
else:
user = self.clients[notified_socket]
type_, data = message['data'].decode("utf-8").split("$")
if(type_ == "message"):
print(f"Recieved Message from {user['data'].decode('utf-8')} : {message['data'].decode('utf-8')} of type {type_}")
for client_socket in self.clients:
if client_socket != notified_socket:
client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])
for notified_socket in exception_sockets:
sockets_list.remove(notified_socket)
del clients[notified_socket]
print(f"Closed connection from {clients[notified_socket]['data'].decode('utf-8')}")
class serverGUI():
def __init__():
window = Tk()
window.title(f"Chatt.py HOSTING SERVER (IP : {IP} \\\\ HOST : {HOST})")
def createWidgets(self):
return False
def log(self, data):
return False
def loop(self):
window.mainloop()
serverBackend = ServerNoGui()
and here's the client
import socket
import select
import errno
import sys
HEADER_LENGTH = 10
IP = socket.gethostbyname("0.0.0.0")#'192.168.0.40'
PORT = 1234
my_username = input("Username: ")
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((IP, PORT))
client_socket.setblocking(False)
username = my_username.encode("utf-8");
username_header = f"{len(username):<{HEADER_LENGTH}}".encode("utf-8")
client_socket.send(username_header + username)
while True:
messageInput = input(f"Me({my_username}) > ")
message = f"message${messageInput}"
if(message):
message = message.encode("utf-8")
message_header = f"{len(message):<{HEADER_LENGTH}}".encode("utf-8")
client_socket.send(message_header + message)
print(f"sent {message_header} : {message}")
try:
while True:
username_header = client_socket.recv(HEADER_LENGTH)
if(not len(username_header)):
print("connection closed by server")
sys.exit()
username_lenght = int(username_header.decode("utf-8").strip())
username = client_socket.recv(username_lenght).decode("utf-8")
message_header = client_socket.recv(HEADER_LENGTH)
message_length = int(message_header.decode("utf-8").strip())
messageRaw = client_socket.recv(message_length).decode("utf-8")
type_, message = messageRaw.split("$")
if(type_ == message):
print(f"{username} >> {message}")
except IOError as e:
if(e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK):
print("READ ERR",str(e))
sys.exit()
continue
except Exception as e:
print("Error".str(e))
sys.exit()
I decided to try with two clients I get the following output
Server:
server started
Starting thread sub-proccesses...
sub-proccesses started!
point
point 0
accepted
Recieved
added to list
created user
Accepted connection from 127.0.0.160338 username: test1
point
point 0
accepted
Recieved
added to list
created user
Accepted connection from 127.0.0.160340 username: test2
point
point 1
Recieved Message from test2 : message$hello of type message
point
point 1
Recieved Message from test1 : message$ of type message
point
point 1
Recieved Message from test1 : message$hello of type message
client1:
Username: test1
Me(test1) >
sent b'8 ' : b'message$'
Me(test1) > hello
sent b'13 ' : b'message$hello'
client2:
Username: test2
Me(test2) > hello
sent b'13 ' : b'message$hello'
as you can see the messages are sent and recieved by the server but not displayed (I'm not stupid I hit enter a few times).
Your server code is confusing and probably not doing what you thought. First you create a thread to accept connections giving it acceptUsers as its thread function (call this thread A). However, that function will only run once in that thread, then it will exit after it has visited all of the read_sockets (because there's no while True loop).
Second, your other thread (B) is running in manageDataSending -- also executing select, but when a client connects, it's calling acceptUsers. That means on the first connection to your server, there's a "race" between the two threads. It's questionable what will happen next because both are now destined to execute the acceptUsers code at more or less the same time, so the exact order of operations in the two threads is now indeterminate.
It's possible that thread A could run first, handle the server_socket (accept the connection and do the receive) and quit, before thread B enters the select call in acceptUsers. That would leave thread B waiting in the select (in acceptUsers) until the next time a client connects or sends data.
On the other hand, it's possible that thread A and thread B both get past the select in acceptUsers and both execute the accept call. Then the accept will succeed in one, and block in the other, waiting for a subsequent incoming connection. In either case, your thread B eventually ends up blocked in a place in your code that you didn't expect it to be.
Bottom line: there's no obvious reason for you to have the two separate threads, both doing a select call. It will be much simpler and easier to understand what is going on if create only one thread, and have it execute your socket select in one place, have that place handle the socket notifications for both incoming connections and incoming client data.
One other thing to note: you don't really need to handle the exception_sockets separately. If one of your clients goes away, its entry in the read_sockets list will be signaled as "ready-to-read" and when you attempt to read it, you will get an end-of-file indication (i.e. zero-length buffer returned).
I'm trying to make a Host/ClientTCP Chat Console.
I have a little problem with my python script, actually, i can't assign my listenS socket when i'm in server mode.
I want to use the same functions (Send and Recieve) for the Client and Host but i don't know if it is possible, i'm not very good in python so if you guys can help me to solve this
Thanks
Code :
import socket
from threading import Thread
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Port = 1604
listenS = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def start():
IP_address = "192.168.1.49"
isserver = input("Server ? (Y/N) : ")
if isserver.lower() == "n":
rIP = input("IP Adress : ")
# str(rIP)
rPort = input("Port : ")
if rPort != "":
Port = int(rPort)
else:
Port = 1604
if isserver.lower() == "n":
listenS.connect((IP_address, Port))
elif isserver.lower() == "y":
Listen()
def Listen():
try:
server.bind(('', Port))
server.listen(10)
listenS, addr = server.accept() # ---- Here is my problem ! -----
except:
print("Connection Timed Out !")
class Send(Thread):
def __init__(self):
Thread.__init__(self)
print("Sender Started...")
def run(self):
while True:
message = input() + "\n"
listenS.send(message.encode('utf-8'))
class Recieve(Thread):
def __init__(self):
Thread.__init__(self)
print("Listener Started...")
def run(self):
while True:
print(listenS)
message = listenS.recv(2048)
print(str(message).replace(r"\n","").replace(r"b'","").replace(r"'",""))
start()
send = Send()
recieve = Recieve()
send.start()
recieve.start()