Unlock recvfrom when socket is closed

Let's say I start a thread to receive on a port. A socket call will be blocked on recvfrom. Then, somehow in another thread, I close the socket.

On Windows, this will unlock recvfrom, and my thread will complete.

On Linux, this does not unlock recvfrom, and as a result, my thread sitting does nothing forever, and the thread does not complete.

Can someone help me with what is happening on Linux? When the socket is closed, I want recvfrom to unlock

I keep reading about using select (), but I don't know how to use it for my specific case.

+5
source share
5 answers

shutdown(sock, SHUT_RDWR) , . (.. pthread_join).

, close() recvfrom(), linux.

+11

select() :

// Note: untested code, may contain typos or bugs
static volatile bool _threadGoAway = false;

void MyThread(void *)
{
   int fd = (your socket fd);
   while(1)
   {
      struct timeval timeout = {1, 0};  // make select() return once per second

      fd_set readSet;
      FD_ZERO(&readSet);
      FD_SET(fd, &readSet);

      if (select(fd+1, &readSet, NULL, NULL, &timeout) >= 0)
      {
         if (_threadGoAway)
         {
            printf("MyThread:  main thread wants me to scram, bye bye!\n");
            return;
         }
         else if (FD_ISSET(fd, &readSet))
         {
            char buf[1024];
            int numBytes = recvfrom(fd, buf, sizeof(buf), 0);
            [...handle the received bytes here...]
         }
      }
      else perror("select");
   }
}

// To be called by the main thread at shutdown time
void MakeTheReadThreadGoAway()
{
   _threadGoAway = true;
   (void) pthread_join(_thread, NULL);   // may block for up to one second
}

, - select ( socketpair()), , I/O, , -, -. .:)

, (, ) , recvfrom() , select() , - , . " " .

+3

, Linux :

, ,      .      , ,      .

+1

. , close, , recvfrom. , , , , .

, , , close recvfrom. close , , recvfrom.

, recvfrom, , close, ( , ). , , close recvfrom .

:

  • - recvfrom, , .
  • close.
  • , - , socket decsriptor, , close d.
  • , recvfrom, .

.

Never done anything like that, even remotely. A resource should not be freed if another thread is being used or can be used. Period.

0
source

When the socket is closed, I want to recvfrom unlock

recvfrom () is a function specific to UDP sockets in Python. Here is a brief overview of how I solved the problem using an idea called “polling” (try running the program, and the print instructions will give you a clear idea of ​​what is going on):

import socket
import threading
import signal
import time

# Custom class to create a socket, close the socket, and poll the socket
class ServerSocket():
    def __init__(self, addresses):
        # "Standard" way to create and preapare a working socket
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.bind(addresses)
    def poll(self):
        self.socket.settimeout(2)
        modifiedMsg, senderAddress = self.socket.recvfrom(1024)
    def close(self):
        self.socket.close()

class ServiceExit(Exception):
    """
    Custom exception which is used to trigger the clean exit
    of all running threads and the main program.
    """
    pass

def service_shutdown(signum, frame):
    raise ServiceExit

# Custom class to create a UDP server on a separate thread.
# This server will know to close the blocking UDP socket when the user
# of the main program signals termination via typing CTRL-C into the terminal
class Server(threading.Thread):
    def __init__(self, addresses):
        threading.Thread.__init__(self)
        self.mysocket = ServerSocket(addresses)
        # This flag below will help us determine when to stop the "run" loop below
        # The while loop below is where interrupt the blocking recvfrom() call by
        # timing out every 2 seconds and checking to see if the flag has been set
        # to discontinue the while loop
        self.shutdown_flag = threading.Event()
    def run(self):
        while not self.shutdown_flag.is_set():
            try:
                print('socket blocking')
                self.mysocket.poll()
            except socket.timeout:
                print('socket unblocked')
                pass
        # as a final step, we close the socket
        self.mysocket.close()
        print('socket closed')

def main():
    # assign the methods that will be called when our main program receives a SIGTERM or SIGINT signal
    # You can send this main problem such a signal by typing CTRL-C after you run this program
    signal.signal(signal.SIGTERM, service_shutdown)
    signal.signal(signal.SIGINT, service_shutdown)

    # Start the server thread that will eventually block on recvfrom()
    try:
        print('starting udp server thread')
        udp_server = Server(('localhost', 5000))
        udp_server.start()
        while True:
            time.sleep(0.5)
        # This server will accept UDP packets on the local host at port 5000
        # Feel free to change these settings to fit your needs
    except ServiceExit:
        print('shutting down server thread')
        udp_server.shutdown_flag.set()
        udp_server.join()
        print('server thread shut down')

if __name__ == '__main__':
    main()
-1
source

All Articles