Скрученный Python - нужно пройти через все соединения и найти клиента - PullRequest
1 голос
/ 23 июля 2011

Я пытаюсь создать простую ваучерную программу.

Клиент подключается к серверу и спрашивает, осталось ли на нем ваучер, если да, то сколько времени отвечает сервер.

У меня есть контроль над сервером и клиентами, клиентская часть также написана мной.

Прямо сейчас это то, что я имею для моей серверной стороны, клиентская часть говорит сама за себя.

Большой недостаток в том, что если 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()

1 Ответ

5 голосов
/ 24 июля 2011

Если ваучер становится «используемым», когда клиент проверяет его, а затем становится неиспользованным, когда клиент отключается, это звучит так, как будто вам просто нужно сохранить набор ваучеров, которые вы добавляете, когда проверка завершена, и удалять из которых, когдаклиент отключаетсяВы можете оставить это на заводе, чтобы оно было общим для всех клиентских подключений.Например:

#!/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()

Новый атрибут vcode в Responder позволяет обновлять набор 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.

...