p2p chat on python

Question:

I wrote p2p chat. The essence of the code is as follows:

  1. The server starts and starts listening on IP and port then several clients are started.
  2. Next, the client enters the /members command. The server sends the client a list of available customers.
  3. After connecting to clients, clients communicate directly without a server.

The server works without errors as it seems to me, and when the client starts, the following File

"d:\p2p_chat.py", line 60, in start_listen listener.bind((host, port)) 
OSError: [WinError 10048] Usually only one use of the socket address (protocol/network address/port) is allowed What is the error and are there any other flaws in the code.

Thanks in advance

#server.py
import socket

TCP_MAX_SIZE=65535


def listen(host: str='127.0.0.1', port: int=9000 ):
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    s.bind((host,port))
    s.listen(0)
    print(f'Listening at {host}:{port}')

    members=[]
    while True:
        conn, addr = s.accept()
        msg=conn.recv(TCP_MAX_SIZE)

        if addr not in members:
            members.append(addr)

        if not msg:
            continue
        client_id=addr[1]
        msg_text=msg.decode('utf-8')
        if msg_text=='__join':
            print(f'Client {client_id} joined chat')
            continue
        message_template='{}__{}'
        if msg_text=='__members':
            print(f'Client {client_id} requsted members')
            active_members=[f'client{m[1]}'for m in members if m!=addr]
            members_msg=';'.join(active_members)
            conn.send(message_template.format('members',members_msg).encode('utf-8'))    

if __name__=='__main__':
    listen()
#client.py
import socket
import os
import random

TCP_MAX_SIZE = 4096

COMMANDS = ['/members', '/exit', '/connect', '/help', '/send']

HELP_TEXT = '''
/members - list members in chat
/connect clientX - connect to clientX
/exit - exit chat
/send path_to_file - send a file
'''

def start_listen(s, host, port):
    def listen():
        while True:
            try:
                conn, addr = s.accept()
            except OSError:
                continue
            
            print(f'Connected by {addr}')
            peer_port = addr[1]
            if peer_port not in listen.allowed_ports:
                conn.close()
                continue
            
            while True:
                data = conn.recv(TCP_MAX_SIZE)
                if not data:
                    print(f'Disconnect from {addr}')
                    break
                
                print(f'client{peer_port}: {data.decode("utf-8")}')
                if data.startswith('__join'):
                    conn.send('__joined'.encode('utf-8'))
                elif data.startswith('__members'):
                    members = [f'client{p}' for p in listen.allowed_ports if p != peer_port]
                    conn.send(('n'.join(members)).encode('utf-8'))
                elif data.startswith('__exit'):
                    print(f'Disconnect from {addr}')
                    conn.close()
                    break
                elif data.startswith('file__'):
                    filename, filesize = data.decode('utf-8').split('__')
                    filesize = int(filesize)
                    with open(filename, 'wb') as f:
                        bytes_received = 0
                        while bytes_received < filesize:
                            chunk = conn.recv(TCP_MAX_SIZE)
                            f.write(chunk)
                            bytes_received += len(chunk)
                    print(f'Successfully received file {filename}, size {filesize} bytes')
                else:
                    print(f'client{peer_port}: {data.decode("utf-8")}')
            
    listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    listener.bind((host, port))
    listener.listen()
    listener.allowed_ports = []
    return listener.listen()

def connect(host='127.0.0.1', port=9000):
    addsr = host, port
    own_port = random.randint(8000, 9000)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((host, own_port))

    listen_thread = start_listen(s, host, port)
    allowed_ports = [port]
    listen_thread.allowed_ports = allowed_ports
    try:
        s.connect((host, port))
        s.send('__join'.encode('utf-8'))
    except OSError as e:
        print(f"Error: {e}")
    
    while True:
        msg = input(f'you: ')

        command = msg.split(' ')[0]
        if command in COMMANDS:
            if msg == '/members':
                s.send('__members'.encode('utf-8'), len(addsr))
            if msg == '/exit':
                peer_port = s.getpeername()[1]
                allowed_ports.remove(peer_port)
                s.close()
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.bind((host, own_port))
                listen_thread = start_listen(s, host, port)
                listen_thread.allowed_ports = allowed_ports
                s.connect((host, port))
                s.send('__exit'.encode('utf-8'))
                print(f'Disconnect from client{peer_port}')
            if msg.startswith('/connect'):
                peer = msg.split(' ')[-1]
                peer_port = int(peer.replace('client', ''))
                allowed_ports.append(peer_port)
                s.close()
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.bind((host, own_port))
                listen_thread = start_listen(s, host, port)
                listen_thread.allowed_ports = allowed_ports
                s.connect((host, port))
                s.send('__join'.encode('utf-8'))
                print(f'Connected to client{peer_port}')
            if msg == '/help':
                print(HELP_TEXT)
            if msg.startswith('/send'):
                filepath = msg.split(' ')[-1]
                filename = os.path.basename(filepath)
                filesize = os.path.getsize(filepath)
                s.send(f'file__{filename}__{filesize}'.encode('utf-8'))
                with open(filepath, 'rb') as f:
                    bytes_sent = 0
                    while bytes_sent < filesize:
                        data = f.read(TCP_MAX_SIZE)
                        s.send(data)
                        bytes_sent += len(data)
                print(f'Successfully sent file {filename}, size {filesize} bytes')
        else:
            s.send(msg.encode('utf-8'))


if __name__ == '__main__':
    connect()
Asked By: Tron

||

Answers:

Your error say you the answer.

If you call the method start_listen in your client.py you need to change the listen port. Your server.py is already listen to port 9000 on localhost.
And your `client.py’ also want to listen on the same port wich is not possible.

Another hint: Close the socket after listen.

Answered By: Luca
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.