如何在等待接收数据时关闭阻塞套接字?

时间:2011-09-27 16:42:16

标签: python sockets networking

我有一个使用阻塞套接字接收数据的服务。我遇到的问题是,如果仍在等待数据,我不知道如何正确关闭套接字。下面是我如何打开和等待数据的简短说明:我不想实现超时,因为根据python文档,套接字必须阻塞才能使用makefile

我可能会对此完全错误,因为我不熟悉使用套接字进行编程。

编辑:

应该注意的是,我无法改变服务器的运行方式。

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
reader = s.makefile("rb")
line = reader.readline()

4 个答案:

答案 0 :(得分:5)

有一个非常简单的解决方案。给定一个套接字和一个读取器文件对象,如rfile = socket.makefile('rb'),为了使rfile.readline()在套接字关闭时立即返回,您需要在一个单独的线程中执行以下操作:

socket.shutdown(socket.SHUT_RDWR)
socket.close()

调用socket.shutdown()会使rfile.readline()返回空strbytes,具体取决于Python的版本(分别为2.x或3.x)。

答案 1 :(得分:1)

我相信如果你只是从另一个线程继续关闭它,那么试图从中读取的线程将返回错误。如果您没有多个线程,则必须重构以使用非阻塞模式(打开套接字时选项os.O_NONBLOCK。)

答案 2 :(得分:1)

关闭此套接字的一个解决方案是要求服务器关闭它。

如果服务器关闭客户端套接字,客户端将收到“按对等方重置连接”错误,并且可能会破坏阻止接收。

另一个解决方案是不使用readline()并在你的套接字上设置超时(无限期等待......无限期等)

答案 3 :(得分:0)

从各种其他有些混乱,往往是脆弱或危险的答案中可以看出,这是一个棘手的问题。幸运的是,您可以通过使用非阻塞套接字来解决所有这些问题。考虑这种方法(为简单起见使用Twisted):

from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineOnlyReceiver
from twisted.protocols.policies import TimeoutMixin
from twisted.internet import reactor

class YourClientProtocol(LineOnlyReceiver, TimeoutMixin):
    def connectionMade(self):
        # Initiate the timeout
        self.setTimeout(30)

    def lineReceived(self, line):
        # Reset the countdown
        self.resetTimeout()
        # And process the line somehow
        if line == "great justice":
            print "for the win!"

    def timeoutConnection(self):
        # Report the timeout
        print "Timed out waiting for a line"
        # Drop the connection
        self.transport.loseConnection()

    def connectionLost(self, reason):
        # Let the program complete
        reactor.stop()

# Set up a connection
clientFactory = ClientFactory()
clientFactory.protocol = YourClientProtocol
reactor.connectTCP(HOST, PORT)

# Start the main loop, which can handle timed and 
# network events simultaneously
reactor.run()