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

Python 如何在阻塞套接字等待接收数据时关闭它?,python,sockets,networking,Python,Sockets,Networking,我有一个使用阻塞套接字接收数据的服务。我的问题是,如果套接字仍在等待数据,我不知道如何正确关闭它。下面是我如何打开和等待数据的简短介绍:我不想实现超时,因为根据python文档,套接字必须阻塞才能使用makefile 我可能完全错了,因为我对使用套接字编程还不熟悉 编辑: 应该注意的是,I不能改变服务器的操作方式 import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT))

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

我可能完全错了,因为我对使用套接字编程还不熟悉

编辑:

应该注意的是,I不能改变服务器的操作方式

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

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

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

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


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

从其他各种有点困惑、往往脆弱或危险的答案中可以看出,这是一个棘手的问题。幸运的是,您可以使用非阻塞套接字来回避所有这些问题。考虑这种方法(使用简单的扭曲):


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


调用将使
rfile.readline()
返回一个空的
str
bytes
,具体取决于Python的版本(分别为2.x或3.x)。

我无权访问服务器。。。但在挠头一段时间后,我想到了编写代理服务器的可能性。。。但这可能过于复杂了……你可能是对的。我花了很多时间试图让readline()工作,而不是自己寻找换行符……实际上,客户端将从readline()接收null,而不是异常。并且没有理由不能将readLine()与套接字超时结合使用。@EJP:根据python文档,您不能将其与具有timeoutHmm的套接字结合使用。python文档还说fgets(3)丢弃了NUL字节,这让我想知道python文档有多准确,如果一个带有超时的套接字被传递到socket.makefile(),会发生什么情况?
EBADF
,至少在我的系统上是这样。但是这是很危险的,除非你绝对确定没有线程会在你关闭套接字后开始读取它——你必须使用互斥锁——否则你最终会遇到一个竞争条件,反对打开新的套接字并获得相同的fd。C中的典型做法是向线程发送一个信号,等待插座信号处理程序可以
longjmp
输出,也可以使用
EINTR
使
读取失败。这对我来说非常有用。谢谢
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()
socket.shutdown(socket.SHUT_RDWR)
socket.close()