良い一日! この記事では、
Twistedと
Wokkelライブラリーを使用して、XMPPプロトコルを使用
して基本的な
パブリッシュ/サブスクライブ実装を作成する方法について説明します。 XMPPは
XEP-0060拡張のおかげでpub / subをサポートします。 pub / subを使用すると、イベントおよびその他多くの参加者すべてに通知する問題を解決できます。 Appleが通知サーバー内でWokkelベースのpub / subを使用していることは確実に知られていますが、それについては後で詳しく説明します。
パブリッシュ/サブスクライブする理由
プロジェクトの開発時に、次のタスクが発生しました。クライアントがサーバーに保存されたデータを使用してアクションを実行するクライアントサーバーアーキテクチャを構築することです。 データはパブリックドメインにあり、クライアントがデータの最新バージョンに基づいて行動する必要があります。 システムの仕組みを少し説明します。 クライアントはサービスにサブスクライブします。 サービスに加入すると、クライアントはサーバーに保存されているすべてのデータを受け取ります。 クライアントはサーバーにデータを送信します。 サーバーは送信されたデータを保存し、すべてのサブスクライバーに転送します。 サブスクライバーは、データの整合性が侵害されていることを発見した場合、サーバーにデータの転送などを依頼します。
ツール
ソリューションは、XMPPとその拡張機能XEP-0060を使用する形で見つかりました。 XMPPが選ばれたのは、その人気と豊富な機能のためです。 Twistedは、Pythonで最も強力なネットワークフレームワークの1つとして選択されました。 Twisted.wordsには基本的なxmppプロトコルのサポートがありますが、残念ながらpub / sub拡張機能のサポートはありません。 Wokkelは、Twistedにpub / subサポートを追加するライブラリーと見なされました。 Wokkelはpub / subだけでなく、(
service discovery )およびその他の便利な拡張機能もサポートしています。
例
Wokkelライブラリの操作方法を示す小さな例を作成してみましょう。 サービスを提供し、顧客はサービスの更新を購読します。 クライアントは5秒ごとにメッセージを生成し、サーバーに送信します。 サーバーは、購読しているすべての参加者にメッセージを送信します。 始めましょう。
まず、サービスであるXMPPClientクラスのオブジェクトを作成する必要があります(Twisted用語)。 彼は、Jabberサーバーの認証と接続管理を担当しています。 PubSubClientまたはPubSubServiceクラスのオブジェクトは、pub / subプロトコルレベルで対話する機能を提供します。 プロトコルとサービスが相互にやり取りできるように、setHandlerParentを呼び出します。 サービスを開始します。 プロトコルは、pub / subに関連するメッセージのスレッドのリッスンを開始し、上記のメッセージを受信すると、対応するハンドラーを呼び出します。 次のステップは、Serviceクラスの実装を検討することです。
def main ( ) :
ログ。 startLogging ( sys。stdout )
オプション、args = parse_args ( )
jid、resource、password = args
サービス=オプション。 奉仕
fulljid = jabber。 jid 。 internJID ( jid + '/' +リソース)
transport = XMPPClient ( fulljid、password )
輸送。 logTraffic = True
protocol = Client ( jabber。jid。internJID ( service ) ) if service else Service ( )
プロトコル。 setHandlerParent ( transport )
輸送。 startService ( )
リアクター。 実行 ( )
この場合、pub / subサービスのタスクは単純です。サブスクライバーからメッセージを受信し、他のすべてのサブスクライバーに送信します。 クライアントは、サブスクリプション要求を送信することにより、サービスとの対話を開始します。 サービスは、サブスクライブ要求が到着したことを認識するとすぐに、サブスクライブメソッドを呼び出します。 このメソッドでは、クライアントに関連付けられたサブスクリプションを作成し、コールバックで返す必要があります。 アクセスモデルを実装せず、誰でも購読できると考えています。 サブスクライバーがデータを送信すると、publishメソッドが呼び出されます。 sendDataメソッドでは、サービスにサブスクライブしている全員に着信データを送信します。 次に、クライアントの検討に移ります。
クラスサービス( PubSubService ) :
def __init__ ( self ) :
PubSubService。 __init__ ( self )
self ._subscriptions = { }
def publish ( self 、requestor、service、nodeIdentifier、items ) :
自己 。 sendData ( items )
延期を返します。 成功 ( なし )
def subscribe ( self 、requestor、service、nodeIdentifier、subscriber ) :
自己 ._subscriptionsのサブスクライバーの場合 :
info = self ._subscriptions [購読者]
その他 :
info =サブスクリプション( NODE_NAME、サブスクライバー、 'subscribed' )
self ._subscriptions [ subscriber ] = info
延期を返します。 成功 (情報)
def sendData ( self 、items ) :
sendList = [ ]
セルフ ._subscriptionsのサブスクリプション。 値 ( ) :
sendList。 追加 ( [ subscription。subscriber、 None 、items ] )
自己 。 notifyPublish ( self。parent。jid 、NODE_NAME、sendList )
クライアントを作成するとき、私たちは彼に彼が購読するサービスのアドレスを与えます。 サービス(XMPPClient)がjabberサーバーで許可され、接続が確立されると、connectionInitializedメソッドがサービス(XMPPClient)に接続されているすべてのプロトコルで呼び出されます。 接続が確立された直後に、必要なサービスのサブスクリプションがサブスクライブされるようにします。 サブスクリプションが正常に完了した後、4秒ごとに発生するイベントを開始し、サービスにメッセージを生成して送信します。 転送されるデータは、適切にフォーマットされたXMLである必要があります。 実際にはそれだけです。
クラス Client ( PubSubClient ) :
def __init__ ( self 、service ) :
PubSubClient。 __init__ ( self )
self .__ service = service
def connectionInitialized ( self ) :
PubSubClient。 connectionInitialized ( self )
d = self サブスクライブ ( self .__ service、NODE_NAME、 self。parent。jid )
d。 addCallback ( lambda success: task。LoopingCall ( sendGeneratedData、 self ) )
d。 addCallback ( lambda lc: lc。start ( 5 、now = True ) )
def itemsReceived ( self 、event ) :
イベントのアイテム。 アイテム :
ログ。 msg ( item。getAttribute ( 'sender' ) + 'sends' +
アイテム。 getAttribute ( 'message' ) + 'at' + item。 getAttribute ( 'time' ) )
def sendData ( self 、items ) :
自己 。 発行 ( self .__サービス、NODE_NAME、アイテム)
def sendGeneratedData (プロトコル) :
element = Element ( ( None 、 'item' ) )
要素。 属性 [ '送信者' ] =プロトコル。 親 jid 。 フル ( )
要素。 属性 [ 'time' ] =時間。 strftime ( "%H:%M:%S" 、時間。localtime ( ) )
要素。 属性 [ 'メッセージ' ] = 'こんにちは!'
プロトコル。 sendData ( [ element ] )
ここでソースコードを見る
操作を確認するには、次のものが必要です。
サーバーの開始:
pubsub.py test@example.comサーバーのパスワード2つのクライアントを実行します:
pubsub.py --service test@example.com/server test@example.com client1 passwordpubsub.py --service test@example.com/server test@example.com client2 passwordAppleはそれと何をしなければなりませんか?
これまでに行ったのは、何百ものpub / sub機能の1つを示す例です。 仕様に目を向けると、設定がpersistItems = False deliveryPayloads = Trueで、所属、検出、他のノードの作成の可能性をサポートしないオープンアクセスモデルで、リーフノードのタイプに対応していることがわかります。 pub / sub仕様全体または必要な部分を実装するのがどれほど難しいか想像してみてください。 しかし、wokkelの作者である
Ralph Meijerはタスクを単純化し、
Idavollを書きました。 IdavollはWokkelのアドオンです。 XEP-0060をほぼ完全にサポートし、http経由で通信する機能があります。 Idavollは、Appleが通知サーバーとして使用します。 この事実は
ここで確認できます
。おわりに
Twistedを学ぶには、公式ドキュメントと
krondo.com/?page_id=1327をお勧めします
残念ながら、Wokkelに関する情報はほとんどありませんが、Idavollに関する情報はまったくないため、生成されたドキュメントのみが残ります。
学習に成功しました!