Python twisted - 需要遍历所有连接寻找客户端
我正在尝试创建一个简单的代金券程序。
客户端连接到服务器,询问代金券是否还有剩余时间,如果有,服务器会回复剩余的时间。
我可以控制服务器和客户端,客户端的代码也是我写的。
现在这是我在服务器端的代码,客户端的部分比较简单明了。
这个程序的一个大问题是,如果两个客户端使用相同的代金券代码连接,它们都会获得访问权限,因为服务器并没有检查是否有其他活跃的客户端在使用这个代码。
有没有人能解释一下,或者提供一些文档,告诉我该怎么解决这个问题?
#!/usr/bin/env python
from twisted.internet import reactor, protocol
class Responder(protocol.Protocol):
def dataReceived(self, data):
# check the voucher code, and return disabled if its out of time or not there. Otherwise return time left.
if data.startswith("check="):
param, vcode = data.split("=")
checkcode = SQLConnect("check", vcode, vcode)
if checkcode == "disabled":
self.transport.write("disabled")
else:
self.transport.write(str(checkcode))
# Update time left.
if data.startswith("update="):
param, vcode, vtime = data.split("=")
SQLConnect("update", vcode, vtime)
def main():
factory = protocol.ServerFactory()
factory.protocol = Responder
reactor.listenTCP(6500,factory)
reactor.run()
if __name__ == '__main__':
main()
1 个回答
如果一个代金券在客户检查时变成“正在使用”,然后在客户断开连接时变成未使用,听起来你只需要维护一组代金券。当检查完成时把代金券加进去,客户断开时把它们移除。你可以把这些代金券放在工厂里,这样所有的客户连接都可以共享。比如:
#!/usr/bin/env python
from twisted.internet import reactor, protocol
class Responder(protocol.Protocol):
def connectionMade(self):
self.vcode = None
def dataReceived(self, data):
# check the voucher code, and return disabled if its out of time or not there. Otherwise return time left.
if data.startswith("check="):
param, vcode = data.split("=")
if vcode in self.factory.activeVouchers:
self.transport.write("in use")
return
self.factory.activeVouchers.add(vcode)
self.vcode = vcode
checkcode = SQLConnect("check", vcode, vcode)
if checkcode == "disabled":
self.transport.write("disabled")
else:
self.transport.write(str(checkcode))
# Update time left.
if data.startswith("update="):
param, vcode, vtime = data.split("=")
SQLConnect("update", vcode, vtime)
def connectionLost(self, reason):
if self.vcode is not None:
self.factory.activeVouchers.remove(self.vcode)
def main():
factory = protocol.ServerFactory()
factory.activeVouchers = set()
factory.protocol = Responder
reactor.listenTCP(6500,factory)
reactor.run()
if __name__ == '__main__':
main()
在Responder
上新增的vcode
属性可以在客户断开连接时更新activeVouchers
集合(这会触发Responder.connectionLost
调用)。在Responder.dataReceived
的开头附近增加的检查会在代金券被使用时把它们加入集合,并防止任何正在使用的代金券被领取。
除此之外,你可能还想考虑其他几个方面。首先,你可能应该使用twisted.protocols.basic.LineOnlyReceiver
或twisted.protocols.basic
中的其他协议,而不是单纯使用Protocol
。dataReceived
会在网络上收到任何字节时被调用。由于TCP是面向流的传输,而不是面向消息的传输,你可能会遇到像dataReceived("chec")
紧接着dataReceived("k=somecode")
这样的情况。按照你现在实现的dataReceived
,这种情况不会被处理,客户将不会收到任何响应。LineOnlyReceiver
增加了基于行的分帧,这样像“check=somecode\r\n”这样的字节可以被解释为完整的消息,并且“check=somecode”会在一次lineReceived
调用中全部传递。
其次,SQLConnect
看起来可能会执行一些阻塞的输入输出操作。如果是这样的话,你的服务器在处理多个客户请求时可能会表现不佳,因为任何阻塞都会阻止所有新事件的处理,包括来自不同客户的事件。你可能想看看twisted.enterprise.adbapi
,它提供了一个非阻塞的SQL API。