I made a chatroom with a server and client python files, using Sockets
and Threading
as a project. I'm interested to acquire advice, and optimizations i could make to my program. Also please give me tips on sockets
and threading
in general, because I'm fairly new to the topic, and i would want to learn whatever is relevant in sockets
in general. Thank you.
Server.py:
import threading
# constants
DISCONNECT_COMMAND = '/disconnect'
HEADER_LENGTH = 10
FORMAT = 'utf-8'
IP = '127.0.1.1'
PORT = 1234
SERVER_ADDRESS = (IP, PORT)
print("[SERVER] Starting Server...")
# creating and listening to socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(SERVER_ADDRESS)
server_socket.listen()
# clients information
clients = {} # {client_socket: {'username': username, 'address': address}}
messages = [] #
def close_connection(client_socket):
print(f"[DISCONNECTION] {clients[client_socket]['username']} has disconnected!")
del clients[client_socket]
client_socket.close()
def send_message(socket, message):
try:
socket.send(bytes(f"{len(message):<{HEADER_LENGTH}}", FORMAT))
socket.send(bytes(message, FORMAT))
except:
print(f"[ERROR] SENDING '{message}' to {clients[socket]['username']}")
def receive_message(client_socket):
while True:
message_length = client_socket.recv(HEADER_LENGTH).decode(FORMAT)
message = client_socket.recv(int(message_length)).decode(FORMAT)
return message
def send_to_all_clients(message, sender_socket):
user_message = f"{clients[sender_socket]['username']} > {message}"
messages.append(user_message)
print(user_message)
for client_socket in clients:
if sender_socket != client_socket:
send_message(client_socket, user_message)
def handle_client(client_socket, client_address):
# user name and server prompt for new connections
username = receive_message(client_socket)
clients[client_socket] = {'username': username, 'address': client_address}
print(f"[ACTIVE CONNECTIONS] {threading.active_count() - 1}")
print(f"[NEW CONNECTION] {username} has connected!")
# server prompt for connection, and receiving previous messages of server.
send_message(client_socket, f'You have connected to the server with the username "{clients[client_socket]["username"]}"!')
send_message(client_socket, str(len(messages))) # sending of previous messages to new client
for i in range(len(messages)):
send_message(client_socket, messages[i])
# receiving messages and sending it to other clients
connected = True
while connected:
try:
message = receive_message(client_socket)
if message == DISCONNECT_COMMAND:
connected = False
send_to_all_clients(message, client_socket)
except:
connected = False
close_connection(client_socket)
# listening for clients
print("[LISTENING] Listening for Clients")
while True:
client_socket, client_address = server_socket.accept()
handling_thread = threading.Thread(target=handle_client, args=[client_socket, client_address])
handling_thread.start()
Client.py:
import socket
import threading
# Server Information
SERVER_ADDRESS = ('127.0.1.1', 1234)
HEADER_LENGTH = 10
FORMAT = 'utf-8'
DISCONNECT_COMMAND = '/disconnect'
def send_message(message):
message_length = f"{len(message):<{HEADER_LENGTH}}"
client_socket.send(bytes(message_length, FORMAT))
client_socket.send(bytes(message, FORMAT))
def receive_message():
while True:
message_length = client_socket.recv(HEADER_LENGTH).decode(FORMAT)
if message_length:
message = client_socket.recv(int(message_length)).decode(FORMAT)
return message
def receive_messages_in_real_time():
while True:
message = receive_message()
print(message)
# Connecting to Server
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(SERVER_ADDRESS)
# Username Prompt
username = input("Enter your username:\n")
send_message(username)
# Server Message for successful connection, and previous messages in server
print(receive_message())
number_of_messages = receive_message()
for _ in range(int(number_of_messages)):
print(receive_message())
# thread for receiving messages
receiving_thread = threading.Thread(target=receive_messages_in_real_time)
receiving_thread.daemon = True
receiving_thread.start()
# messaging in the server
connected = True
while connected:
message = input()
send_message(message)
if message == DISCONNECT_COMMAND:
connected = False