Perlを勉強する合間に、分け合って(というか授業の関係で)Twistedを使うことになった。しかし、あまりにも日本語のドキュメントがなくて悲しい思いをしたので、自分のために肝の部分だけココにメモっておこうかと思う。
TwistedについてははTwistedスプリント - Python Developers Camp 2006 Summerが日本語でくわしいところのかなり上位っぽい。
ほんとはTwistedはかなりいろんなことができるようなのだけど、うちも使いはじめたばかりなので、一番基本的っぽいTCPによるサーバクライアントなコードをてっとりばやく書くのに必要なポイントだけを。
使うもの
以下の三つがあれば、とりあえずクライアントとサーバが書ける。
- Protocol
- Factory
- reactor
最低限Protocolのコードを書けば良くて、Factoryとreactorは使うだけでもなんとか。とりあえず、
from twisted.internet.protocol import Protocol from twisted.internet.protocol import Factory from twisted.internet import reactor
を書いとく。
Protocol
Protocolはコネクションごとに生成されるオブジェクトのクラス。コネクションごとの処理は全部プロトコルクラスのサブクラスに実装する。いくつかコールバック関数が用意されていて、使いそうなのは、
- connectionMade: コネクションが成立したときに呼ばれる
- dataReceived: データを受信したときに呼ばれる
- connectionLost: コネクションを破棄したときに呼ばれる
あたり。Protocolクラスのサブクラスではこのメソッドをオーバーライドすることになる。もちろん自分のメソッドもかけるけど。
class ServerProtocol(Protocol): def dataReceived(self, data): # ここでサーバが受信したデータを処理する self.transport.write("You said " + data + ".\n")
このコードのように、データを送信するにはself.transport.writeを使えば良い。
Factory
実際にサーバをRunするのが後述するreactorなんだけれども、このFactoryはreactorとProtocolの仲介をする。コネクションごとのProtocolオブジェクトは生成元のFactoryの参照をもつので、コネクション全体で共有したいようなデータはFactoryのインスタンスに持たせると良い。
class ServerProtocol(Protocol): def dataReceived(self, data): # self.factoryの要素は、どのProtocolインスタンスからも見える self.factory.log.append(data)
以下のreactorの例のコードではFactoryクラスのインスタンスを直接作成しているが、自分でサブクラスを書いたり、便利なコールバックが用意されているより強力なFactoryクラスもある。Client書くときはClientFactoryなんかのサブクラスを作った方が手っ取り早いのかも。
reactor
サーバを実際にRunしているのがreactor。protocolをセットしたFactoryをセットして使う。
factory = Factory() factory.protocol = ServerProtocol reactor.listenTCP(8800, factory) reactor.run()
クライアントを作る場合は、より強力なClientFactoryをクライアント向けのconnectTCPメソッドに渡すととより便利。
てなかんじ
うちは、コネクション毎の処理をProtocolに、コネクション全体の統合をFactoryに、ほかのいろんな処理はメインルーチンで、最後にrunするのはreactorという一連のながれを掴むのに、なかなか時間がかかった。ここに書いとけば、未来の自分がまったく忘れてもはやくおもいだせるやも。Twisted Documentation: Twisted Documentationにあるチュートリアルを少し読んで、なんとかコード書いてるのだけれど、このドキュメントがなかなか不親切で、Twistedの全体像がつかみにくい。せめて日本語だと良いのになぁ。