如何从Python中的另一个线程中止socket.recv()

发布于 09-02 21:58 字数 1419 浏览 12 评论 0原文

我有一个等待连接的主线程。它生成客户端线程,该线程将回显来自客户端的响应(在本例中为 telnet)。但是假设我想在一段时间后关闭所有套接字和所有线程,例如在 1 个连接之后。

我该怎么做呢?如果我从主线程执行 clientSocket.close() ,它不会停止执行 recv 。仅当我首先通过 telnet 发送某些内容时它才会停止,然后它将无法执行进一步的发送和接收。

我的代码如下所示:

# 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()

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()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

栀子花开つ2024-09-09 21:58:58

我知道这是一个旧线程,塞缪尔可能很久以前就解决了他的问题。然而,我遇到了同样的问题,并在谷歌搜索时发现了这篇文章。找到解决方案并认为值得添加。

您可以在套接字类上使用 shutdown 方法。它可以阻止进一步的发送、接收或两者。

socket.shutdown(socket.SHUT_WR)

例如,

上面的内容会阻止将来的发送。 有关更多信息,请参阅 Python 文档。

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.

当梦初醒2024-09-09 21:58:58

我不知道是否可以按照您的要求进行操作,但应该没有必要。如果没有什么可读的,就不要从套接字读取;使用 select.select 检查套接字中的数据。

更改:

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

更像这样:

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

编辑:如果您想防止套接字已关闭的可能性,请捕获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)

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)
孤云独去闲2024-09-09 21:58:58

我找到了使用超时的解决方案。这将中断接收(实际上在超时到期之前,这很好):

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


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

    def run(self):
        while 1:
            try:
                data = self.clientSocket.recv(1024)
                print "Got data: ", data
                self.clientSocket.send(data)
            except socket.timeout: 
                # If it was a timeout, we want to continue with recv
                continue
            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()
clientSocket.settimeout(1)

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

# Close it down immediatly 
clientSocket.close()

I found a solution using timeouts. That will interrupt the recv (actually before the timeout has expired which is nice):

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


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

    def run(self):
        while 1:
            try:
                data = self.clientSocket.recv(1024)
                print "Got data: ", data
                self.clientSocket.send(data)
            except socket.timeout: 
                # If it was a timeout, we want to continue with recv
                continue
            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()
clientSocket.settimeout(1)

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

# Close it down immediatly 
clientSocket.close()
还不是爱你2024-09-09 21:58:58

我必须为下面的评论道歉。 @Matt Anderson 的早期评论有效。我在尝试时犯了一个错误,这导致了我在下面的帖子。

使用超时并不是一个很好的解决方案。瞬间醒来然后重新进入睡眠状态似乎没什么大不了的,但我发现它极大地影响了应用程序的性能。您有一个操作,在大多数情况下都希望阻塞,直到数据可用,从而永远休眠。但是,如果您出于某种原因想要中止,例如关闭应用程序,那么技巧就是如何退出。对于套接字,您可以在两个套接字上使用 select 和 Listen。你的主要的,和一个特殊的关闭的。不过,创建关闭功能有点痛苦。你必须创建它。你必须让监听套接字接受它。您必须跟踪该管道的两端。我对同步队列类也有同样的问题。但是,您至少可以在队列中插入一个虚拟对象来唤醒 get()。但这要求虚拟对象看起来不像您的正常数据。有时我希望 Python 有类似 Windows API WaitForMultipleObjects 的东西。

I must apologize for the comments below. The earlier comment by @Matt Anderson works. I had made a mistake when trying it out which led to my post below.

Using timeout is not a very good solution. It may seem that waking up for an instant and then going back to sleep is no big deal, but I have seen it greatly affect the performance of an application. You have an operation that for the most part wants to block until data is available and thus sleep forever. However, if you want to abort for some reason, like shutting down your application, then the trick is how to get out. For sockets, you can use select and listen on two sockets. Your primary one, and a special shutdown one. Creating the shutdown one though is a bit of a pain. You have to create it. You have to get the listening socket to accept it. You have to keep track of both ends of this pipe. I have the same issue with the Synchronized Queue class. There however, you can at least insert a dummy object into the queue to wake up the get(). This requires that the dummy object not look like your normal data though. I sometimes wish Python had something like the Windows API WaitForMultipleObjects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文