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()
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
vcodeattribute onResponderlets theactiveVouchersset get updated when the client disconnects (which triggers theResponder.connectionLostcall). The additional check near the beginning ofResponder.dataReceivedadds 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.LineOnlyReceiveror one of the other protocols intwisted.protocols.basicinstead of justProtocol.dataReceivedis 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 yourdataReceivedis implemented now, this case won’t be handled and the client will receive no response.LineOnlyReceiveradds 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 singlelineReceivedcall.Second,
SQLConnectlooks 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.adbapifor a non-blocking SQL API.