Unblock recvfrom when socket is closed

前端 未结 5 1270
自闭症患者
自闭症患者 2020-12-07 01:44

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

On Windows, this will

5条回答
  •  無奈伤痛
    2020-12-07 02:24

    When the socket is closed, I want recvfrom to unblock

    recvfrom() is a function specific to UDP sockets on Python. Here's a brief summary of how I solved the problem using an idea referred to as "polling" (try running the program as well, the print statements will give you a solid idea of whats 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()
    

提交回复
热议问题