0

I'm coding a school excercise using UDP sockets in python and I need to exchange some information (e.g., ints, strings, etc.) between server and client.

I wrote this functions to asure a message sent from the server is received on the client side and vice versa:

import socket

BUFFER_SIZE = 1024

def send_udp_mgs(origin, destination, msg):
    msg = str(msg).encode('utf8')
    origin.sendto(msg, destination) # sending message
    # I never receive confirmation
    opt, _ = origin.recvfrom(BUFFER_SIZE) # Code stucks here
    opt = opt.decode('utf8')
    print(opt)

def receive_udp_msg(destination):
    msg, origin = destination.recvfrom(BUFFER_SIZE) # receiving message OK
    # This is the message sent as confirmation but is never received
    destination.sendto("CHECK".encode('utf8'), origin) # sent but not received
    msg = msg.decode()
    return msg

I would expect the code to work properly with the function receiving the confirmation after sending the message but it gets stuck waiting for the confirmation. The client sends the confirmation but the server never receives it. Other than that, the client receives the message well, it's only the confirmation back to the server that fails.

This is the server code:

def client_thread (s, c):
    print("Connection petition from", c)
    global n_cons
    cport = PORT + n_cons
    send_udp_mgs(s, c, cport)
    return

# UDP socket acting as server
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((IP, PORT))
while True:
    data, addr = s.recvfrom(BUFFER_SIZE)
    if data.decode() == CONNECT:
        n_cons += 1
        try:
            Thread(target=client_thread, args=(s,), kwargs={'c':addr}).start()
        except:
            print("Error creating thread")
            break

Client code

c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s = (IP, PORT)
# Connecting to the server
c.sendto(CONNECT.encode('utf8'), s)
cport = receive_udp_msg(c)
charcoal
  • 3
  • 3
  • 1
    How are you calling these functions? In particular, are they running as different processes? If so, how are you setting up the sockets. – jirassimok Oct 17 '19 at 03:34
  • I make a thread for each client on the server side, while the client is running on the "main" function. So the send_udp_mgs is on a thread on the server side, while receive_udp_msg is on the main the client – charcoal Oct 18 '19 at 20:44
  • The code you posted works fine on its own, so my guess is that the problem is something going on in the server. Could you show us some of the code that runs the server? (My first suspicion is that it's some sort of threading problem.) – jirassimok Oct 18 '19 at 22:27
  • I added the server and client code. – charcoal Oct 23 '19 at 17:26

1 Answers1

0

I wasn't able to get your program to stop at the exact point you said it stops at, but I was able to find an issue I suspect has a similar cause:

With more than one client, the thread waiting for confirmation from one client can receive the CONNECT message from the next client, and the server's "main loop" can receive the confirmation message.

You can't avoid this problem: unless you can control when all clients send data, you can't spin off threads for different clients when you're using UDP. I recommend using select, selectors, or asyncio, or just asyncio's socket functions to perform actions on your sockets.

But here's something else to consider: why are you trying to confirm UDP messages? If you need to make sure the other end of the connection receives what you send, why aren't you using TCP or some other protocol that has mechanisms for ensuring delivery built-in?

If you really need to use UDP, you'll need to make at least one data structure to keep track of the clients who are trying to "connect," and other information about their "connections." But UDP is explicitly connectionless.


As an unrelated comment, does the cport in client_thread imply that you plan to create a new port, in sequential order, for each client? If so, consider that (a) you can only have so many ports open, (b) another process many be using one of those ports, (c) unless n_cons never goes down, this process will be using those ports, and (d) what do you need that many ports for? (See also this answer.)

jirassimok
  • 3,850
  • 2
  • 14
  • 23
  • 1
    Thanks so much for your answer. I know that the most logical thing to do would be to use TCP, but it's a school excersise with UDP. I will take into account everything you said, thanks again! – charcoal Oct 28 '19 at 04:29