Difference between revisions of "Twisted"

From JaWiki (Jabber/XMPP wiki)
Jump to: navigation, search
m (Пример клиентского приложения: отступы)
m (исправил мелкие огрехи; добавил про поддерживаемые протоколы)
 
(12 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 
{{Library
 
{{Library
 
|            name=Twisted
 
|            name=Twisted
|              url=http://twistedmatrix.com/trac/
+
<!--      Общая информация          -->
|        language=[[Python]]
+
|              url=[http://twistedmatrix.com/ twistedmatrix.com]
}}[[Category:Python]][[Category:Python_Library]]
+
|        language={{Lang|l|Python}}
 +
|        xmlparser=внутренний (twisted.words.xish)
 +
<!--        Реализация стандартов  -->
 +
|          roster=нет
 +
<!-- |    filetransfer=пересылка файлов -->
 +
|        dataforms=нет
 +
|            disco=нет
 +
|            adhoc=нет
 +
|              zip=нет
 +
|          pubsub=нет
 +
|              pep=нет
 +
|          jingle=нет
 +
|              jid=да
 +
|            sasl=да
 +
|        component=да
 +
}}
  
'''Twisted''' -- framework для написания сетевых приложений.  
+
'''Twisted'''&nbsp;— фрэймворк для написания сетевых приложений на [[Python]].
Предоставляет механизмы для легкой реализации сетевого сервера и клиента.  
+
Предоставляет механизмы для легкой реализации сетевого сервера и клиента.
Есть классы облегчающие реализацию своего протокола, а также уже реализована обработка большого числа существующих протоколов, в том числе и XML-потока [[Jabber]]-а.  
+
Есть классы облегчающие реализацию своего протокола, а также уже реализована обработка большого числа существующих протоколов, в том числе и XML-потока [[Jabber]]-а.
  
Но работа Twisted не ограничивается только сетью.  
+
Но работа Twisted не ограничивается только сетью.
 
Этот фреймворк облегчает создание расширяемых с помощью плагинов программ, конструирование многосервисных программ, создание единой авторизации пользователей между сервисами и многое другое.
 
Этот фреймворк облегчает создание расширяемых с помощью плагинов программ, конструирование многосервисных программ, создание единой авторизации пользователей между сервисами и многое другое.
  
 +
Работа с [[XMPP]] реализована в модуле <code>twisted.words</code>, который, кроме того, поддерживает {{proto|lib|IRC}}, {{proto|lib|MSN}} (MSNP8, полуэкспериментальная поддержка) и {{proto|lib|OSCAR}}.
  
 
== Для начинающего Twisted-разработчика ==
 
== Для начинающего Twisted-разработчика ==
В отличии от многих других [[Library|библиотек]] и фреймворков для реализации Jabber-приложений, в twisted-e обработка нескольких клиентских соединений производится не через потоки или процессы, а через конечный автомат ([http://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82 FSM]).
+
В отличие от многих других [[библиотека|библиотек]] и фреймворков для реализации Jabber-приложений, в Twisted обработка нескольких клиентских соединений производится не через потоки или процессы, а через {{w|конечный автомат}}. Это означает, что всех клиентов обслуживает, грубо говоря, ''один поток и один цикл'', а вся ответственность за «параллелизацию» работы c клиентами ложится на плечи программиста, а не ОС. Такой подход признан более эффективным, но и более сложным в исполнении.
Это заставляет при написании приложения придерживаться нескольких правил:
+
# Функция не должна долго думать. Так как практически все соединения обрабатываются в одном потоке и в одном цикле, то каждая пауза сказывается на всех. Поэтому "долгие" задачи должны быть выделены в отдельный поток, который в конце работы передаст результат с помощью вызова функции в общем цикле (например с помощью twisted.internet.threads.deferToThread).
+
# Вся работа с внешними и потенциально-тормознутыми данными, это базы данных, сеть и даже работа с файлами, по тем же причинам должна быть разделена на две части (обычно через объект Deferred):
+
## Первая отправляет запрос
+
## Вторая (callback) обрабатывает результат когда он появится.
+
# Вся работа с сетью осуществляется в небезопасном, с точки зрения потоков, режиме. Поэтому для отправки в сеть каких-либо данных из потока необходимо воспользоваться специальными функциями, которые вставят отправку в общий цикл (reactor.callFromThread)
+
  
== Для Jabber разработчика ==
+
К счастью, вся сложная часть уже реализована в Twisted, а программисту остается только создавать свои обработчики событий и придерживаться нескольких правил:
Реализация Jabber протокола находится в пакете twisted.words.protocols.jabber.  
+
# Функция не должна долго думать. Так как все соединения обрабатываются в одном потоке и в одном цикле, то каждая пауза сказывается на всех. Поэтому «долгие» задачи (большие вычисления и&nbsp;т.&nbsp;п.) должны быть выделены в отдельный поток, который в конце работы вернет результат с помощью вызова функции в общем цикле (создание потока и возврат результата можно облегчить с помощью <code>twisted.internet.threads.deferToThread</code>).
{{Todo|про создание и отправку станз}}
+
# Вся работа с внешними и потенциально-тормознутыми данными, а это базы данных, сеть и даже работа с файлами, по тем же причинам должна быть разделена на две части (обычно через объект Deferred): первая отправляет запрос, вторая (callback) обрабатывает результат, когда он появится. Для такой работы с большой частью тормознутых объектов уже подготовлены нужные классы.
 +
# Вся работа с сетью осуществляется в небезопасном, с точки зрения потоков, режиме. Поэтому для отправки в сеть каких-либо данных из потока (если вы все же решили выделить отдельный) необходимо воспользоваться специальными функциями, которые вставят отправку в общий цикл (<code>reactor.callFromThread</code>). То же касается и других вещей, которые в многопоточной программе требовали блокировок.
 +
 
 +
== Для Jabber-разработчика ==
 +
Реализация Jabber протокола находится в пакете <code>twisted.words.protocols.jabber</code>.
 +
{{Todo|про создание и отправку стансов}}
 
{{Todo|про создание обработчиков}}
 
{{Todo|про создание обработчиков}}
  
 
=== Пример клиентского приложения ===
 
=== Пример клиентского приложения ===
Пример простого бота для Jabber-сервера ([http://yoan.dosimple.ch/blog/2007/01/30/ источник])
+
Пример простого бота для Jabber-сервера ([http://yoan.dosimple.ch/blog/2007/01/30/ источник], адаптирован для работы с Twisted 2.5.0)
  
 
  # Эти модули понадобятся.
 
  # Эти модули понадобятся.
  from twisted.words.protocols.jabber import client, jid
+
  from twisted.words.protocols.jabber import client, jid, xmlstream
  from twisted.xish import domish, xmlstream
+
  from twisted.words.xish import domish
 
  from twisted.internet import reactor
 
  from twisted.internet import reactor
 
   
 
   
Line 38: Line 53:
 
  me = jid.JID("greutly@swissjabber.ch/TwistedWords")
 
  me = jid.JID("greutly@swissjabber.ch/TwistedWords")
 
   
 
   
  # Так как бот -- это клиентское приложение, то и factory (см выше)  
+
  # Так как бот -- это клиентское приложение, то и factory (см. [http://twistedmatrix.com/projects/core/documentation/howto/glossary.html#Factory глоссарий])  
  # тоже будет клиентским. Библиотека twisted.words.protocols.jabber.client
+
  # тоже будет клиентским. Модуль twisted.words.protocols.jabber.client
 
  # предоставляет класс для создания factory Jabber-клиентов.
 
  # предоставляет класс для создания factory Jabber-клиентов.
 
  factory = client.basicClientFactory(me, "password")
 
  factory = client.basicClientFactory(me, "password")
Line 46: Line 61:
 
  # что-то вроде "открыть сокет, подождать ответ, послать логин/пароль,  
 
  # что-то вроде "открыть сокет, подождать ответ, послать логин/пароль,  
 
  # подождать и т.д." тоже нельзя. Для того, чтобы выполнить какие-то
 
  # подождать и т.д." тоже нельзя. Для того, чтобы выполнить какие-то
  # определенные действия после авторизации, наеобходимо создать callback:
+
  # определенные действия после авторизации, необходимо создать callback:
 
  def authd(xmlstream):
 
  def authd(xmlstream):
 
     # создание XML элемента presence.
 
     # создание XML элемента presence.
Line 65: Line 80:
 
  # пришло.
 
  # пришло.
 
  def gotMessage(message):
 
  def gotMessage(message):
     # sorry for the __str__(), makes unicode happy
+
     # sorry for the str(), makes unicode happy
 
     print u"from: %s" % message["from"]
 
     print u"from: %s" % message["from"]
 
     for e in message.elements():
 
     for e in message.elements():
 
         if e.name == "body":
 
         if e.name == "body":
        print unicode(e.__str__())
+
            print unicode(str(e))
        break
+
            break
 
   
 
   
 
  # Теперь регистрация callback-а authd.
 
  # Теперь регистрация callback-а authd.
Line 82: Line 97:
  
 
== Ссылки ==
 
== Ссылки ==
[[:Category:Twisted]]
 
 
== См. также ==
 
 
* [http://www.opennet.ru/base/dev/server_way.txt.html Подходы к организации серверного приложения]
 
* [http://www.opennet.ru/base/dev/server_way.txt.html Подходы к организации серверного приложения]
 
* [http://twistedmatrix.com/documents/current/api/ Twisted API]
 
* [http://twistedmatrix.com/documents/current/api/ Twisted API]
* [http://twistedmatrix.com/projects/core/documentation/howto/index.html Twisted документация]
+
* [http://twistedmatrix.com/projects/core/documentation/howto/index.html Документация]
* [http://twistedmatrix.com/projects/core/documentation/howto/tutorial/index.html пример реализации протоколо Finger с помощью Twisted]
+
* [http://ru.pywiki.com/index.php/Twisted Twisted на русскоязычной Python wiki]
 +
* [http://twistedmatrix.com/projects/core/documentation/howto/tutorial/index.html Пример реализации] протокола {{w|Finger}} с помощью Twisted

Latest revision as of 21:10, 11 July 2010

Twisted
Информация
Адрес: twistedmatrix.com
Язык: Python
XML-парсер: внутренний (twisted.words.xish)
Реализация стандартов
Анализ JID-а: да
SASL-авторизация: да
Регистрация компонента: да
Ростер: нет
Data Forms: нет
Service Discovery: нет
Ad-Hoc команды: нет
Сжатие XML потока: нет
PubSub: нет
PEP: нет
Jingle: нет
Использование
Программы, использующие Twisted

Twisted — фрэймворк для написания сетевых приложений на Python. Предоставляет механизмы для легкой реализации сетевого сервера и клиента. Есть классы облегчающие реализацию своего протокола, а также уже реализована обработка большого числа существующих протоколов, в том числе и XML-потока Jabber-а.

Но работа Twisted не ограничивается только сетью. Этот фреймворк облегчает создание расширяемых с помощью плагинов программ, конструирование многосервисных программ, создание единой авторизации пользователей между сервисами и многое другое.

Работа с XMPP реализована в модуле twisted.words, который, кроме того, поддерживает IRC, MSN (MSNP8, полуэкспериментальная поддержка) и OSCAR.

Для начинающего Twisted-разработчика[edit]

В отличие от многих других библиотек и фреймворков для реализации Jabber-приложений, в Twisted обработка нескольких клиентских соединений производится не через потоки или процессы, а через конечный автомат. Это означает, что всех клиентов обслуживает, грубо говоря, один поток и один цикл, а вся ответственность за «параллелизацию» работы c клиентами ложится на плечи программиста, а не ОС. Такой подход признан более эффективным, но и более сложным в исполнении.

К счастью, вся сложная часть уже реализована в Twisted, а программисту остается только создавать свои обработчики событий и придерживаться нескольких правил:

  1. Функция не должна долго думать. Так как все соединения обрабатываются в одном потоке и в одном цикле, то каждая пауза сказывается на всех. Поэтому «долгие» задачи (большие вычисления и т. п.) должны быть выделены в отдельный поток, который в конце работы вернет результат с помощью вызова функции в общем цикле (создание потока и возврат результата можно облегчить с помощью twisted.internet.threads.deferToThread).
  2. Вся работа с внешними и потенциально-тормознутыми данными, а это базы данных, сеть и даже работа с файлами, по тем же причинам должна быть разделена на две части (обычно через объект Deferred): первая отправляет запрос, вторая (callback) обрабатывает результат, когда он появится. Для такой работы с большой частью тормознутых объектов уже подготовлены нужные классы.
  3. Вся работа с сетью осуществляется в небезопасном, с точки зрения потоков, режиме. Поэтому для отправки в сеть каких-либо данных из потока (если вы все же решили выделить отдельный) необходимо воспользоваться специальными функциями, которые вставят отправку в общий цикл (reactor.callFromThread). То же касается и других вещей, которые в многопоточной программе требовали блокировок.

Для Jabber-разработчика[edit]

Реализация Jabber протокола находится в пакете twisted.words.protocols.jabber.

ToDo: про создание и отправку стансов
ToDo: про создание обработчиков

Пример клиентского приложения[edit]

Пример простого бота для Jabber-сервера (источник, адаптирован для работы с Twisted 2.5.0)

# Эти модули понадобятся.
from twisted.words.protocols.jabber import client, jid, xmlstream
from twisted.words.xish import domish
from twisted.internet import reactor

# Для JID-а используем специальный Twisted-класс
me = jid.JID("greutly@swissjabber.ch/TwistedWords")

# Так как бот -- это клиентское приложение, то и factory (см. глоссарий) 
# тоже будет клиентским. Модуль twisted.words.protocols.jabber.client
# предоставляет класс для создания factory Jabber-клиентов.
factory = client.basicClientFactory(me, "password")

# FSM полностью строится на callback-ах. Ждать нельзя. Поэтому писать 
# что-то вроде "открыть сокет, подождать ответ, послать логин/пароль, 
# подождать и т.д." тоже нельзя. Для того, чтобы выполнить какие-то
# определенные действия после авторизации, необходимо создать callback:
def authd(xmlstream):
   # создание XML элемента presence.
   presence = domish.Element(('jabber:client', 'presence'))
   presence.addElement('status').addContent('Online')
 
   # отправка в xmlstream. Обратите внимание, что это безопасная отправка,
   # так как эта функция вызывалась из главного цикла и в данный момент мы 
   # единственные, кто сейчас работает с потоком. Остальные, если есть, ждут.
   xmlstream.send(presence)
 
   # Установка обработчика на входящие XML-элементы message. Первый 
   # параметр -- это XPath
   xmlstream.addObserver('/message', gotMessage)

# сам обработчик. параметр message -- XML-элемент
# основная функция обработчика -- печатать то, что 
# пришло.
def gotMessage(message):
   # sorry for the str(), makes unicode happy
   print u"from: %s" % message["from"]
   for e in message.elements():
       if e.name == "body":
           print unicode(str(e))
           break

# Теперь регистрация callback-а authd.
factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, authd)

# И последнее:
# Создание главного реактора для клиентского TCP соединения
reactor.connectTCP("swissjabber.ch", 5222, factory)
# Запуск реактора
reactor.run()

Ссылки[edit]