The chat server will handle multiple clients, allowing them to send messages to each other. We will use socket for networking and select for managing multiple connections.
import socket
import select
# Define constants for server
HOST = '127.0.0.1' # Localhost
PORT = 12345 # Port to bind the server
# Create a socket object with IPv4 (AF_INET) and TCP (SOCK_STREAM)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the address and port
server_socket.bind((HOST, PORT))
# Enable the server to accept connections (5 is the max number of queued connections)
server_socket.listen(5)
# List of sockets for select.select()
sockets_list = [server_socket]
# Dictionary to keep track of connected clients and their addresses
clients = {}
print(f"Chat server started on {HOST}:{PORT}")
def receive_message(client_socket):
"""
Receive messages from a client socket.
"""
try:
# Receive message header indicating the message length
message_header = client_socket.recv(10)
# If no data, client has closed the connection
if not len(message_header):
return False
# Decode message header to get the length
message_length = int(message_header.decode('utf-8').strip())
# Receive the actual message
return {'header': message_header, 'data': client_socket.recv(message_length)}
except:
# Something went wrong, possibly connection reset
return False
while True:
# Use select to wait for activity on the sockets
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
for notified_socket in read_sockets:
# If the notified socket is the server socket, it means a new connection
if notified_socket == server_socket:
client_socket, client_address = server_socket.accept()
user = receive_message(client_socket)
if user is False:
continue
sockets_list.append(client_socket)
clients[client_socket] = user
print(f"Accepted new connection from {client_address[0]}:{client_address[1]} username:{user['data'].decode('utf-8')}")
else:
# For any other socket, it means an existing client is sending a message
message = receive_message(notified_socket)
if message is False:
# Client disconnected, cleanup
print(f"Closed connection from {clients[notified_socket]['data'].decode('utf-8')}")
sockets_list.remove(notified_socket)
del clients[notified_socket]
continue
user = clients[notified_socket]
print(f"Received message from {user['data'].decode('utf-8')}: {message['data'].decode('utf-8')}")
for client_socket in 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]
import socket
import select
HOST = '127.0.0.1'
PORT = 12345
socket: Provides low-level networking interface.select: Monitors multiple sockets, waiting until they become readable, writable, or have an error.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(5)
sockets_list = [server_socket]
clients = {}
print(f"Chat server started on {HOST}:{PORT}")
socket.socket(): Creates a new socket using IPv4 and TCP.bind(): Associates the socket with a specific network interface and port.listen(): Enables the server to accept connections; 5 is the maximum number of queued connections.sockets_list: Contains all sockets to monitor with select.clients: Dictionary to store client sockets and their information.def receive_message(client_socket):
try:
message_header = client_socket.recv(10)
if not len(message_header):
return False
message_length = int(message_header.decode('utf-8').strip())
return {'header': message_header, 'data': client_socket.recv(message_length)}
except:
return False
recv(10): Receives the first 10 bytes from the socket, which contain the message length.message_header.decode('utf-8').strip(): Decodes the header to get the message length.client_socket.recv(message_length): Receives the actual message.while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
for notified_socket in read_sockets:
if notified_socket == server_socket:
client_socket, client_address = server_socket.accept()
user = receive_message(client_socket)
if user is False:
continue
sockets_list.append(client_socket)
clients[client_socket] = user
print(f"Accepted new connection from {client_address[0]}:{client_address[1]} username:{user['data'].decode('utf-8')}")
else:
message = receive_message(notified_socket)
if message is False:
print(f"Closed connection from {clients[notified_socket]['data'].decode('utf-8')}")
sockets_list.remove(notified_socket)
del clients[notified_socket]
continue
user = clients[notified_socket]
print(f"Received message from {user['data'].decode('utf-8')}: {message['data'].decode('utf-8')}")
for client_socket in 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]
select.select(): Monitors sockets for readability.notified_socket is the server socket, accept new connections.notified_socket is a client socket, receive the message and broadcast it to all other clients.The client will connect to the server, send messages, and receive messages from other clients.
import socket
import threading
HOST = '127.0.0.1'
PORT = 12345
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))
username = input("Enter your username: ")
username_header = f"{len(username):<10}".encode('utf-8')
client_socket.send(username_header + username.encode('utf-8'))
def receive_messages():
while True:
try:
while True:
username_header = client_socket.recv(10)
if not len(username_header):
print("Connection closed by the server")
return
username_length = int(username_header.decode('utf-8').strip())
username = client_socket.recv(username_length).decode('utf-8')
message_header = client_socket.recv(10)
message_length = int(message_header.decode('utf-8').strip())
message = client_socket.recv(message_length).decode('utf-8')
print(f"{username}: {message}")
except Exception as e:
print("Error receiving message:", str(e))
client_socket.close()
break
def send_messages():
while True:
message = input()
if message:
message_header = f"{len(message):<10}".encode('utf-8')
client_socket.send(message_header + message.encode('utf-8'))
receive_thread = threading.Thread(target=receive_messages)
receive_thread.start()
send_thread = threading.Thread(target=send_messages)
send_thread.start()
import socket
import threading
HOST = '127.0.0.1'
PORT = 12345
socket: Provides low-level networking interface.threading: Enables concurrent execution for sending and receiving messages.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))
socket.socket(): Creates a new socket using IPv4 and TCP.connect(): Connects to the server specified by HOST and PORT.username = input("Enter your username: ")
username_header = f"{len(username):<10}".encode('utf-8')
client_socket.send(username_header + username.encode('utf-8'))
username_header: Creates a header indicating the length of the username.send(): Sends the header and the username to the server.def receive_messages():
while True:
try:
while True:
username_header = client_socket.recv(10)
if not len(username_header):
print("Connection closed by the server")
return
username_length = int(username_header.decode('utf-8').strip())
username = client_socket.recv(username_length).decode('utf-8')
message_header = client_socket.recv(10)
message_length = int(message_header.decode('utf-8').strip())
message = client_socket.recv(message_length).decode('utf-8')
print(f"{username}: {message}")
except Exception as e:
print("Error receiving message:", str(e))
client_socket.close()
break
recv(10): Receives the first 10 bytes, which contain the username/message length.def send_messages():
while True:
message = input()
if message:
message_header = f"{len(message):<10}".encode('utf-8')
client_socket.send(message_header + message.encode('utf-8'))
message_header: Creates a header indicating the length of the message.send(): Sends the header and the message to the server.receive_thread = threading.Thread(target=receive_messages)
receive_thread.start()
send_thread = threading.Thread(target=send_messages)
send_thread.start()
threading.Thread: Creates threads for receiving and sending messages.start(): Starts the threads.By following this detailed implementation and explanation, you can set up a basic chat server and client using Python sockets, allowing multiple clients to communicate with each other in real time.