Сделайте твистер-сервер инициативным - PullRequest
3 голосов
/ 20 сентября 2011

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

Но, скажем, клиент просит сервер выполнить длительный расчет. Я хочу, чтобы сервер периодически отправлял клиенту сообщение о ходе выполнения. Когда сервер проявляет инициативу и вызывает sendLine без запроса со стороны клиента, он, похоже, ждет, пока клиент отправит сообщение на сервер, прежде чем что-либо отправлять.

Как я могу немедленно отправить сообщение с сервера клиенту, не запрашивая у клиента явного запроса?

Ответы [ 3 ]

2 голосов
/ 21 сентября 2011

Используйте deferreds, если вы выполняете вычисления асинхронно.
Другой способ, если это долгий расчет в отдельном потоке, который начинается, скажем, с помощью deferrToThread (), используйте реактор.callFromThread ()
(Я предполагаю, что мы не делаем тяжелые вычисления в основном цикле - это очень, очень неправильно :)) маленький пример:

def some_long_foo(data_array, protocol):
    def send_msg(msg, protocol):
        # It actually looks petter in classes without pushing protocol here and
        # there
        protocol.transport.write(msg)

    for n, chunk in enumerate(data_array):
        do_something_cool(chunk)
        if n and (n % 10 == 0):
            from twisted.internet import reactor
            # here send_msg will be safely executed in main reactor loop
            reactor.callFromThread(send_msg, '10 more chunks processed',
                                   protocol)

# Somwhere in lineReceived we start long calculation
def cb(result):
    self.transport.write('got result: {}'.format(result))
d = threads.deferToThread(some_long_foo, data_array, self)
d.addCallback(cb)

Таким образом, теперь мы будем уведомлять клиента об обработке каждых 10 фрагментов данных, а затем, наконец, отправлять ему результат. код может быть немного неправильным, это просто, например,

документы

UPD: просто для уточнения: пропустил часть sendLine. Обычно это не имеет значения, называйте это insted of transport.write ()

1 голос
/ 23 сентября 2011

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

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

0 голосов
/ 20 сентября 2011

Если под «немедленно» вы подразумеваете «при подключении клиента», попробуйте позвонить sendLine в connectionMade.

вашего подкласса LineReceiver.
...