Twisted: Как я могу определить протокол при начальном соединении, а затем передать его соответствующей реализации протокола? - PullRequest
3 голосов
/ 29 февраля 2012

Я пишу программу на Python, которая будет использовать Twisted для подключения к TCP-серверу. На сервере на другом конце сокета может быть запущен один из двух возможных протоколов (protoA или protoB), но я не буду знать, какой это, пока я не установил соединение и не «спросил» сервер, какой протокол используется. используемый. Я могу определить, какая версия протокола (protoA или protoB) используется после подключения, но заранее не знаю.

Очевидно, что одно решение состоит в том, чтобы в моем классе, извлеченном из протокола, было много специального кода - то есть, если protoA сделал это, elif protoB сделал бы что-то еще. Однако я хотел бы иметь возможность хранить код для двух отдельных протоколов в двух отдельных реализациях протокола (хотя они могут совместно использовать некоторые функции через базовый класс). Поскольку обе версии протокола предусматривают сохранение состояния, может возникнуть путаница, когда нужно смешать обе версии в одном классе.

Как я могу это сделать? Есть ли способ выполнить начальный шаг «идентификации протокола» в реализации Factory, а затем создать правильную производную протокола?

Ответы [ 2 ]

4 голосов
/ 29 февраля 2012

Вместо того, чтобы смешивать логику принятия решений во всей реализации протокола, поместите ее в одном месте.

class DecisionProtocol(Protocol):
    def connectionMade(self):
        self.state = "undecided"

    def makeProgressTowardsDecision(self, bytes):
        # Do some stuff, eventually return ProtoA() or ProtoB()

    def dataReceived(self, bytes):
        if self.state == "undecided":
            proto, extra = self.makeProgressTowardsDecision(bytes)
            if proto is not None:
                self.state = "decided"
                self.decidedOnProtocol = proto
                self.decidedOnProtocol.makeConnection(self.transport)
                if extra:
                    self.decidedOnProtocol.dataReceived(extra)

        else:
            self.decidedOnProtocol.dataReceived(bytes)

    def connectionLost(self, reason):
        if self.state == "decided":
            self.decidedOnProtocol.connectionLost(reason)

В конечном итоге вы сможете реализовать это с немного меньшим количеством шаблонов: http://tm.tl/3204/

1 голос
/ 01 марта 2012

Это легко сделать с помощью магии.

class MagicProtocol(Protocol):
    ...
    def dataReceived(self, data):
        protocol = self.decideProtocol(data)
        for attr in dir(protocol):
            setattr(self, attr, getattr(protocol, attr))

Это некрасиво, но эффективно отключит магический протокол для выбранного протокола.

...