Python Socket Programming: 'Bad file descriptor' Error with Multiple Client Instances

31 views Asked by At

I'm working on a simple chat application using Python's socket programming and RSA encryption for secure communication. The application consists of two scripts: client.py and server.py. The server script handles incoming connections and forwards messages between clients, while the client script allows users to send and receive messages.

When I run two instances of client.py to simulate a chat session and start sending messages between them, the messages do not appear on the other client. Additionally, after sending two messages from the second client instance, I encounter the following error:

Exception in thread Thread-2 (write):
Traceback (most recent call last):
  File "/opt/homebrew/Cellar/[email protected]/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py", line 1045, in _bootstrap_inner
    self.run()
  File "/opt/homebrew/Cellar/[email protected]/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py", line 982, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/xxxxxx/client.py", line 35, in write
    client.send(encrypted_message)
OSError: [Errno 9] Bad file descriptor

Here's a brief overview of how the client and server scripts handle communication:

  1. The client script generates RSA key pairs and exchanges public keys with the server.
  2. Messages sent from a client to the server are encrypted with the server's public key.
  3. The server then forwards these messages to other clients, encrypting the message with each receiving client's public key.

Server.py

import socket
import threading
import rsa

# Generate RSA keys for the server
server_public_key, server_private_key = rsa.newkeys(2048)

clients = []
client_public_keys = {}

def broadcast(message, sender_socket):
    for client in clients:
        if client != sender_socket:  # Avoid sending the message back to the sender
            client_public_key = client_public_keys[client]
            encrypted_message = rsa.encrypt(message.encode(), client_public_key)
            client.send(encrypted_message)

def handle_client(client):
    while True:
        try:
            message = client.recv(1024)
            broadcast(message, client)
        except:
            index = clients.index(client)
            clients.remove(client)
            client.close()
            break

def receive():
    host = '127.0.0.1'
    port = 5551  # Example port, adjust as needed
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((host, port))
    server.listen(2)
    print(f'Server listening on {host}:{port}')

    while True:
        client, address = server.accept()
        print(f"Connected with {str(address)}")

        # Send server public key to client
        client.send(server_public_key.save_pkcs1('PEM'))

        # Receive client's public key
        client_public_key_pem = client.recv(1024)
        client_public_key = rsa.PublicKey.load_pkcs1(client_public_key_pem)
        client_public_keys[client] = client_public_key

        clients.append(client)
        thread = threading.Thread(target=handle_client, args=(client,))
        thread.start()

receive()

Client.py

import socket
import threading
import rsa

# Generate RSA keys for the client
client_public_key, client_private_key = rsa.newkeys(1024)

alias = input("Choose an alias: ")

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 5551))  # Ensure this matches the server's IP and port

# Receive server's public key
server_public_key_pem = client.recv(1024)
server_public_key = rsa.PublicKey.load_pkcs1(server_public_key_pem)

# Send client's public key to server
client.send(client_public_key.save_pkcs1('PEM'))

def receive():
    while True:
        try:
            message = client.recv(1024)
            decrypted_message = rsa.decrypt(message, client_private_key).decode()
            print(decrypted_message)
        except:
            print("An error occurred!")
            client.close()
            break

def write():
    while True:
        message = f'{alias}: {input("")}'
        encrypted_message = rsa.encrypt(message.encode(), server_public_key)
        client.send(encrypted_message)

receive_thread = threading.Thread(target=receive)
receive_thread.start()

write_thread = threading.Thread(target=write)
write_thread.start()

I'm looking for insights on why the messages are not being displayed to each other and why the second client instance throws a "Bad file descriptor" error after sending a couple of messages. Any advice on debugging this issue or suggestions on how to improve the communication flow would be greatly appreciated.

0

There are 0 answers