Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I abort a socket.recv() from another thread in Python

I have a main thread that waits for connection. It spawns client threads that will echo the response from the client (telnet in this case). But say that I want to close down all sockets and all threads after some time, like after 1 connection.

How would I do it? If I do clientSocket.close() from the main thread, it won't stop doing the recv. It will only stop if I first send something through telnet, then it will fail doing further sends and recvs.

My code looks like this:

# Echo server program
import socket
from threading import Thread
import time

class ClientThread(Thread):
    def __init__(self, clientSocket):
            Thread.__init__(self)
            self.clientSocket = clientSocket

    def run(self):
            while 1:
                    try:
                            # It will hang here, even if I do close on the socket
                            data = self.clientSocket.recv(1024)
                            print "Got data: ", data
                            self.clientSocket.send(data)
                    except:
                            break

            self.clientSocket.close()

HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)

clientSocket, addr = serverSocket.accept()
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()

time.sleep(1)

# This won't make the recv in the clientThread to stop immediately,
# nor will it generate an exception
clientSocket.close()
like image 929
Samuel Skånberg Avatar asked May 26 '10 17:05

Samuel Skånberg


People also ask

How do you stop a recv socket?

In your case, you should be able to change the socket into non-blocking mode by calling ioctlsocket() then close it upon exiting the recv() call.

How do you remove a socket from a thread in Python?

To close the connection, break the while loop. Garbage collection will remove the thread or process but join will ensure none get left behind. Persistent sockets close when the user closes them or they timeout. Non-persistent, like static webpages will close after they've sent the information.

How does Python socket recv work?

The recv method receives up to buffersize bytes from the socket. When no data is available, it blocks until at least one byte is available or until the remote end is closed. When the remote end is closed and all data is read, it returns an empty byte string.


2 Answers

I know this is an old thread and that Samuel probably fixed his issue a long time ago. However, I had the same problem and came across this post while google'ing. Found a solution and think it is worthwhile to add.

You can use the shutdown method on the socket class. It can prevent further sends, receives or both.

socket.shutdown(socket.SHUT_WR)

The above prevents future sends, as an example.

See Python docs for more info.

like image 63
cebru Avatar answered Oct 23 '22 16:10

cebru


I don't know if it's possible to do what you're asking, but it shouldn't be necessary. Just don't read from the socket if there is nothing to read; use select.select to check the socket for data.

change:

data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)

to something more like this:

r, _, _ = select.select([self.clientSocket], [], [])
if r:
    data = self.clientSocket.recv(1024)
    print "Got data: ", data
    self.clientSocket.send(data)

EDIT: If you want to guard against the possibility that the socket has been closed, catch socket.error.

do_read = False
try:
    r, _, _ = select.select([self.clientSocket], [], [])
    do_read = bool(r)
except socket.error:
    pass
if do_read:
    data = self.clientSocket.recv(1024)
    print "Got data: ", data
    self.clientSocket.send(data)
like image 41
Matt Anderson Avatar answered Oct 23 '22 17:10

Matt Anderson