Getting a ConnectionResetError when client script is stopped on UDP socket

Viewed 257

I am making a script that will allow multiple clients to see live camera footage from the server script, this all works fine until one of the client scripts is closed, then a ConnectionResetError is raised, To avoid this I used a try and except block to catch the ConnectionResetError but the same error is raised every time after a connection is lost. Using just socket.recv stops the ConnectionResetError but socket.recv does not return the senders address which is required for the script to send the video stream back to the client.

Server:

host = "0.0.0.0"
port = 5000
buffer_size = 1024

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("", port))

listeners = list()  # the addresses of the clients that want the video stream

def handle_queue(sock):
    while True:
        try:
            message, address = sock.recvfrom(buffer_size)  # block the thread until a packet arrives
            print(address)
            message = str(message, "utf-8")  # decode the message
            if message == "join":
                listeners.append(address)  # add the list of listeners
            else:
                print("unknown queue msg: ", message)
        except ConnectionResetError:
            print("The connection was forcefully quit")
        

queue_handler_thread = Thread(target=handle_queue, args=(sock,), daemon=True)
queue_handler_thread.start()  # start the queue


the script then uses sock.sendto() for each address in the listeners list

Client:

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sock.sendto(bytes("join","utf-8"), (host, port))

while True:
    data, address = sock.recvfrom(max_length)  # block main thread until a packet is received
    
2 Answers

I believe what you are looking for is socket.getpeername().

This will return the remote address to which the socket is connected.

Your approach in handling the data in the wire whilst the connection is closed/lost is the right way. Handling via try/catch or using a recv() or recvfrom() method to wait for a response before closing the socket.

Since posting this i have discovered that it is infact TCP and this will not work for the project I am trying to do. Any more guidance and help would be appreciated, I cant seem to find any examples of Multiclient UDP Servers that run through one socket.

I partially resolved my system, after using the Example provided by AztCrw4282. I was able to find a solution, I instead used the socket.accept() aproach, I am unsure as to whether this is UDP or TCP (I want UDP but with the connect system I think that is the handshake for TCP, but I am not 100% sure), but it works for now.

The client has to connect to the server then the server will accept or deny the connection, upon accepting a thread will be created for that clients connection to be managed. If any errors are thrown when interacting with that client their connection will be closed.

Server

try:
    ServerSocket.bind((host, port))
except socket.error as e:
    print(str(e))

print('Waiting for a Connection..')
ServerSocket.listen(5)

connections = list()

def threaded_client(connection):
    connection.send(str.encode('Welcome to the Server\n'))
    while True:
        try:
            data = str(connection.recv(2048),"utf-8")  # this needs to be try catched
            print("Packet Recv: ", data)
            if data == "join":
                print("Client Joined")
            if data == "quit":
                break
            if not data:
                break
        except ConnectionResetError:
            break
    print("Closing a connection")  # need to handle leaving the stream
    connection.close()

def handle_stream():
    for connection in connections:
        try:
            connection.send(bytes(json.dumps(frame_info) ,"utf-8"))
        except:
            print("Packet send failure, kicking client")
            connections.remove(connection)

while True:
    Client, address = ServerSocket.accept()
    print('Connected to: ' + address[0] + ':' + str(address[1]))
    connections.append(Client)
    Thread(target=threaded_client, args=(Client, ), daemon=True).start()
    ThreadCount += 1
    print('Thread Number: ' + str(ThreadCount))

The only part that changes for the client is the part where it connects to the server

try:
    ClientSocket.connect((host, port))
except socket.error as e:
    print(str(e))
Related