2013-06-04 7 views
4

Я пытаюсь задуматься о том, как заставить Twisted выполнять из-за отсутствия лучшего слова «интерактивное» поведение клиента/сервера.Интерактивный клиент/сервер Python с Twisted

Мне удалось собрать пару классов Protocol и ClientFactory, которые подключаются к службе и выполняют немедленный запрос/ответ (см .: connectionMade -> self.queryStatus). Это преуспевает, как ожидалось, и выводит ответ сервера из класса Factory.

Моя проблема заключается в том, что у меня будут внешние события, которые должны вызывать передачу данных, всегда прислушиваясь к потенциальным входящим данным. Но как только цикл reactor.run() будет идти, я не уверен, как остальное мое приложение предназначено для запуска отправки данных.

Я попробовал несколько различных подходов, поскольку, но это самый простой подход, который сделал обрабатывать ПРИЕМ часть, как описано:

class myListenerProtocol(LineReceiver): 
    delimiter = '\n' 

    def connectionMade(self): 
     print("Connected to: %s" % self.transport.getPeer()) 
     self.queryStatus(1) 

    def dataReceived(self, data): 
     print("Receiving Data from %s" % self.transport.getPeer()) 
     ... 
     self.commandReceived(self.myData) 

    def commandReceived(self, myData): 
     self.factory.commandReceived(myData) 

    def connectionLost(self, reason): 
     print("Disconnected.") 

    def queryStatus(self, CommandValue): 
     ... 
     strSend = CommandValue # or some such 
     self.transport.write(strSend) 

class mySocketFactory(ClientFactory): 
    protocol = myListenerProtocol 

    def __init__(self): 
     pass 

    def buildProtocol(self, address): 
     proto = ClientFactory.buildProtocol(self, address) 
     return proto 

    def commandReceived(self, myData): 
     print myData 
     reactor.stop() # It won't normally stop after recv 

    def clientConnectionFailed(self, connector, reason): 
     print("Connection failed.") 
     reactor.stop() 


def main(): 
    f = mySocketFactory() 
    reactor.connectTCP("10.10.10.1", 1234, f) 
    reactor.run() 

Я полагаю, что это довольно прямо вперед, но бесчисленные часы в многочисленных примеры и документация оставили меня без хорошего понимания того, как я должен заниматься этим сценарием.

ответ

-1

Ну, есть много подходов к этому, и лучший из них действительно зависит от контекста вашего приложения, поэтому я не буду подробно останавливать вас на одном из способов сделать это здесь, а скорее свяжу вас с чтением, которое я недавно прочитал на новости хакера:

и хороший пример использования случая, хотя это не относится к тому, что вы работаете (или вы можете прочитать его):

Кстати, вы также можете взглянуть на GEvent или торнадо, которые хороши при обработке такого рода вещей.

Если другие «события» происходят из GUI инструментария (например, GTK или QT) быть действительно осторожны GIL, и даже если вы просто хотите событие командной строки вам необходима тема, и по-прежнему быть осторожными того, что.

Наконец, если вы хотите сделать больше взаимодействия, вы можете написать для своего сервера разные «сверстники», которые взаимодействуют с различными используемыми вами случаями (один клиент, который подключается к графическому интерфейсу, другой с CLI, другой с базой данных, другой с API SAAS и т. д.).

Другими словами, если ваш дизайн не работает, попробуйте изменить свою перспективу!

+0

Вам не нужно быть осторожным с GIL. Просто не используйте потоки. Ничто в этом сообщении не подразумевает необходимости в потоках, поэтому GIL не имеет значения. – Glyph

1

Моя проблема в том, что у меня будут внешние события, которые должны вызывать передачу данных, всегда прислушиваясь к потенциальным входящим данным. Но как только цикл reactor.run() будет идти, я не уверен, как остальное мое приложение предназначено для запуска отправки данных.

"Внешние события"? Как что? Данные, поступающие по соединению? Отлично, если запустить реактор, вы действительно сможете обрабатывать эти данные.

Возможно, кто-то нажал кнопку в графическом интерфейсе?Попробуйте один из интеграционных реакторов GUI - опять же, вы не сможете справиться с этими событиями до тех пор, пока не начнете работать реактор.

Вы, вероятно, застреваете, потому что думаете, что ваша главная функция должна сделать reactor.run(), а затем дальше делать другие вещи. Это не так, как это работает. Когда вы пишете управляемую событиями программу, вы определяете все источники событий, а затем позволяете циклу событий вызывать обработчики, когда события поступают в эти источники.

+1

Нет, я имел в виду, что я буду включать его в качестве компонента более крупного приложения. Например, например, это будет клиентский компонент, работающий, подключенный, в фоновом режиме, в то время как вы используете основное приложение с графическим интерфейсом. Таким образом, событие происходит в основном (существующем) приложении. Не имеет значения, что запускает его, но это заставит этот подключенный клиентский сеанс отправлять данные. Между тем, он будет принимать входящие соединения, и мне придется их обрабатывать. – Dave

+0

Неважно, что вызывает его, потому что именно это будет определять, как вы интегрируете различные компоненты. Если вы хотите полностью игнорировать, как реализуются другие компоненты, запустите их в отдельных процессах и используйте какой-то IPC/RPC. Это, как правило, больше работы, но это самый простой способ совместной работы двух компонентов, если вы не хотите вообще указывать, как каждый из них будет реализован. –

+0

И если это не ясно, я думаю, вы * должны * просто указать, как будет работать ваш другой компонент, а затем выяснить, как его интегрировать в цикл Twisted event. Вышеупомянутый комментарий на тот случай, если вы этого не сделаете. –

Смежные вопросы