0

I have a program which runs on 2 threads. The main thread is for its own work and the other thread keeps calling recv() on a UDP socket.

Basically, the code structure looks like this:

done = False

def run_sock():
   sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   sock.bind(('localhost', 12345))
   while not done:  # receive data until work done
        data = sock.recv(1500)
        print(data)
   sock.close()

thread = threading.Thread(target=run_sock, daemon=True)
thread.start()

# Main thread
while not done:
    ... # Do work here
    if some_condition:  # Stop running, thread should as well
        done = True

thread.join()

I want to close the socket when the main thread changes done to True, but when that happens, the socket is still in its current blocking recv call and it has to receive another message before it finally stops.

Is there a way to gracefully close the socket (without having to handle errors)? I've tried sock.shutdown(socket.SHUT_RDWR), sock.setblocking(False) and but they all raise errors.

Mike Pham
  • 437
  • 6
  • 17
  • miiiiight want to use a mutex or similar threadsafe structure to communicate between threads – Will May 30 '19 at 11:53
  • https://stackoverflow.com/questions/409783/socket-shutdown-vs-socket-close – Will May 30 '19 at 11:56
  • @Will this is just an overly simplified version of what I'm currently working on. I don't want any redundant code because I don't think thread safety is the issue here – Mike Pham May 30 '19 at 11:57
  • sock.recv(1500) should block forever if it doesn't get data so `done` is never checked and sock.close() never called – Will May 30 '19 at 12:08
  • Yes, that's what my question is about. – Mike Pham May 30 '19 at 12:13

1 Answers1

0

So sock.recv(1500) will block until it receives something. If it receives nothing, then it waits.

But if you set a timeout then periodically that wait will throw an exception and you can do other stuff (like look at the done flag) before trying to read again.

sock.settimeout(1.0)
sock.bind(...)

while not done:
    try:
        data = sock.recv(1500)
    except timeout:
        continue
sock.close()

Of course, if the remote end closes the connection that is different. Then you need to look at data to see if it is empty.

while not done:
    try:
        data = sock.recv(1500)
        if not data:
            break
    except timeout:
        continue
Will
  • 1,532
  • 10
  • 22