如何从Python中的另一个线程中止socket.recv()
我有一个等待连接的主线程。它生成客户端线程,该线程将回显来自客户端的响应(在本例中为 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 技术交流群。
发布评论
评论(4)
我不知道是否可以按照您的要求进行操作,但应该没有必要。如果没有什么可读的,就不要从套接字读取;使用 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)
我找到了使用超时的解决方案。这将中断接收(实际上在超时到期之前,这很好):
# 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()
我必须为下面的评论道歉。 @Matt Anderson 的早期评论有效。我在尝试时犯了一个错误,这导致了我在下面的帖子。
使用超时并不是一个很好的解决方案。瞬间醒来然后重新进入睡眠状态似乎没什么大不了的,但我发现它极大地影响了应用程序的性能。您有一个操作,在大多数情况下都希望阻塞,直到数据可用,从而永远休眠。但是,如果您出于某种原因想要中止,例如关闭应用程序,那么技巧就是如何退出。对于套接字,您可以在两个套接字上使用 select 和 Listen。你的主要的,和一个特殊的关闭的。不过,创建关闭功能有点痛苦。你必须创建它。你必须让监听套接字接受它。您必须跟踪该管道的两端。我对同步队列类也有同样的问题。但是,您至少可以在队列中插入一个虚拟对象来唤醒 get()。但这要求虚拟对象看起来不像您的正常数据。有时我希望 Python 有类似 Windows API WaitForMultipleObjects 的东西。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我知道这是一个旧线程,塞缪尔可能很久以前就解决了他的问题。然而,我遇到了同样的问题,并在谷歌搜索时发现了这篇文章。找到解决方案并认为值得添加。
您可以在套接字类上使用 shutdown 方法。它可以阻止进一步的发送、接收或两者。
例如,
上面的内容会阻止将来的发送。 有关更多信息,请参阅 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.
The above prevents future sends, as an example.
See Python docs for more info.