我有一个使用阻塞套接字接收数据的服务。我遇到的问题是,如果仍在等待数据,我不知道如何正确关闭套接字。下面是我如何打开和等待数据的简短说明:我不想实现超时,因为根据python文档,套接字必须阻塞才能使用makefile
。
我可能会对此完全错误,因为我不熟悉使用套接字进行编程。
编辑:
应该注意的是,我无法改变服务器的运行方式。
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
reader = s.makefile("rb")
line = reader.readline()
答案 0 :(得分:5)
有一个非常简单的解决方案。给定一个套接字和一个读取器文件对象,如rfile = socket.makefile('rb')
,为了使rfile.readline()
在套接字关闭时立即返回,您需要在一个单独的线程中执行以下操作:
socket.shutdown(socket.SHUT_RDWR)
socket.close()
调用socket.shutdown()
会使rfile.readline()
返回空str
或bytes
,具体取决于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()