简体   繁体   中英

Stop a blocking python thread after timeout

I'm having an issue that is really difficult to find an already made solution for it.

I'm running a new python thread that is then blocked by a socket connection (python-socketio) because it is waiting indefinitely for data. But I need to close this thread after 5 minutes. I've tried to setup a timer that would close the thread with sys.exit() but I found that this was closing the timer thread itself.

Here is the code so far:

class LiveMatches(commands.Cog):
    def __init__(self, client):
        self.client = client 

    def connect_to_scorebot(self, id):
        feed = MatchFeed(self.client)
        feed.main(id) # when this function is called, 
# it will block the newly created thread to receive the data with the socket

    def create_thread(self, id):
        # we create the thread and call launch_match that will connect to
        # the scorebot
        new_thread = threading.Thread(target=self.connect_to_scorebot, args=(id,))
        # start the thread
        new_thread.start()

A couple of options:

  1. You can set a timeout on the the socket used in the thread so that it returns from blocking after a period of time.
  2. Use select.select() with a timeout to poll a socket for data, periodically checking if the thread should exit.

Example of #1:

import threading
import socket
import select

# A server that echos only the first data received from a client
def server():
    s = socket.socket()
    s.bind(('',5000))
    s.listen()
    print('server: running')
    while True:
        c,a = s.accept()
        print('server: client connected')
        with c: # closes client socket when with block exits
            echoed = False
            while True:
                data = c.recv(1024)
                if not data: break
                if not echoed:
                    print('server: responding',data)
                    c.sendall(data)
                    echoed = True
        print('server: client disconnected')

def client():
    s = socket.socket()
    s.connect(('localhost',5000))
    with s: # closes client socket when with block exits
        try:
            s.settimeout(5) # 5-second timeout if no data received.
            print('client: send one')
            s.sendall(b'one')
            print('client: got',s.recv(1024))
            print('client: send two')
            s.sendall(b'two')
            print('client: got',s.recv(1024))  # this will timeout
        except socket.timeout:
            print('client: timed out')

# Start server thread.
# As a daemon, it will exit if main thread and client thread both exit.
threading.Thread(target=server,daemon=True).start()

t = threading.Thread(target=client)
t.start()
t.join() # wait for client thread to exit.
t = threading.Thread(target=client)
t.start()
t.join() # wait for client thread to exit.

Output:

server: running
client: send one
server: client connected
server: responding b'one'
client: got b'one'
client: send two
client: timed out
server: client disconnected
client: send one
server: client connected
server: responding b'one'
client: got b'one'
client: send two
client: timed out

Note server didn't print that the second client disconnected. Since it is a daemon thread, it was terminated when the main thread and client thread both exited, and didn't have time to recognize the client disconnected after timeout. If you want cleaner exit behavior, don't use daemon threads.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM