18

我有一个等待连接的主线程。它生成客户端线程,这些线程将回显来自客户端的响应(在本例中为 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()
4

4 回答 4

26

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

您可以在套接字类上使用关闭方法。它可以防止进一步的发送、接收或两者兼而有之。

socket.shutdown(socket.SHUT_WR)

例如,以上内容可防止将来发送。

有关更多信息,请参阅 Python 文档。

于 2011-06-19T16:39:36.473 回答
9

我不知道是否可以按照您的要求进行操作,但这不是必需的。如果没有可读取的内容,请不要从套接字读取;用于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)
于 2010-05-26T17:57:19.060 回答
3

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

# 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()
于 2010-05-26T18:20:13.470 回答
2

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

使用超时不是一个很好的解决方案。看起来一瞬间醒来然后重新入睡没什么大不了的,但我已经看到它极大地影响了应用程序的性能。您有一个操作在大多数情况下想要阻止,直到数据可用并因此永远休眠。但是,如果您出于某种原因想要中止,例如关闭您的应用程序,那么诀窍就是如何退出。对于套接字,您可以在两个套接字上使用选择和侦听。您的主要设备和特殊关机设备。创建关机虽然有点痛苦。你必须创造它。您必须让侦听套接字接受它。您必须跟踪此管道的两端。我对同步队列类有同样的问题。然而,那里,您至少可以在队列中插入一个虚拟对象以唤醒 get()。这要求虚拟对象看起来不像您的正常数据。我有时希望 Python 有类似 Windows API WaitForMultipleObjects 的东西。
于 2011-12-14T02:58:12.077 回答