Python 扭曲 - 需要遍历所有连接并找到客户端
我正在尝试创建一个简单的优惠券程序。
客户端连接到服务器并询问凭证是否还有剩余时间,如果是,服务器会响应多少时间。
我控制服务器和客户端,客户端也由我编码。
现在这就是我的服务器端的内容,客户端是不言自明的。
其中最大的缺陷是,如果 2 个客户端使用相同的优惠券代码连接,它们都将具有访问权限,因为服务器不会检查是否存在具有该代码的活动客户端。
任何人都可以解释或提供有关这如何可能的文档吗?
#!/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()
I am trying to create a simple voucher program.
Client connects to server and asks if a voucher has time left on it, if yes the server responds with how much time.
I have control of the server and the clients, the client side is coded by me as well.
Right now this is what I have for my server side, the client side is self explanatory.
The big flaw in this, is that if 2 clients connect with the same voucher code, they will both have access because the server is not checking if there is an active client with that code.
Could anyone explain or lead to documentation in how this is possible ?
#!/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()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果凭证在客户端检查时变为“正在使用”,然后在客户端断开连接时变为未使用,听起来您只需要保留一组凭证,在检查完成时添加到其中,并在客户端断开连接时将其删除。您可以将其保留在工厂中,以便在所有客户端连接之间共享。例如:
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
看起来可能会执行一些阻塞 I/O。如果这是真的,则意味着您的服务器无法很好地处理并发客户端请求,因为任何阻塞都会阻止处理所有新事件,包括来自不同客户端的事件。您可能想查看一下twisted.enterprise.adbapi
的非阻塞 SQL API。If a voucher becomes "in use" when a client checks it and then becomes unused when the client disconnects, it sounds like you just need to keep a set of vouchers which you add to when the check is done and remove from when the client disconnects. You could keep this on the factory so it is shared between all client connections. For example:
The new
vcode
attribute onResponder
lets theactiveVouchers
set get updated when the client disconnects (which triggers theResponder.connectionLost
call). The additional check near the beginning ofResponder.dataReceived
adds vouchers to that set when they become used and prevents any in use voucher from being claimed.Apart from that, there are a couple other things you might want to consider. First, you should probably use
twisted.protocols.basic.LineOnlyReceiver
or one of the other protocols intwisted.protocols.basic
instead of justProtocol
.dataReceived
is called whenever any bytes are received over the network. Since TCP is a stream-oriented transport rather than a message-oriented transported, you may end up with a call likedataReceived("chec")
quickly followed bydataReceived("k=somecode")
. As yourdataReceived
is implemented now, this case won't be handled and the client will receive no response.LineOnlyReceiver
adds line-based framing, so that bytes like "check=somecode\r\n" can be interpreted as a complete message and "check=somecode" delivered all at once, in a singlelineReceived
call.Second,
SQLConnect
looks like it probably performs some blocking I/O. If this is true, it means that your server won't handle concurrent client requests very well, since any blocking prevents all new events from being handled, including those from different clients. You might want to take a look attwisted.enterprise.adbapi
for a non-blocking SQL API.