2009年12月22日火曜日

Twistedでcometする一歩目

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Python:Twistedの短いソースコードのコード(下)を起点にできる限り単純なcometなコードを書こう。

from twisted.internet import reactor, protocol

class MyProtocol(protocol.Protocol):
def connectionLost(self, reason):
pass

def dataReceived(self, data):
print data
self.transport.write('test message\n')
self.transport.loseConnection()

class TCPServer(protocol.ServerFactory):
def buildProtocol(self, addr):
return MyProtocol()

reactor.listenTCP(12345, TCPServer())
reactor.run()


まずは動きを理解するためにそのまま実行。

サーバ側

[nori@shinano]~/Desktop/work/jsboard/comet/sample% python twisted-server.py
hello



クライアント側

[nori@shinano]~/Desktop/work/jsboard/comet/sample% telnet 127.0.0.1 3165
Trying 127.0.0.1...
Connected to shinano.tonic-water.com (127.0.0.1).
Escape character is '^]'.
hello
test message
Connection closed by foreign host.

self.transport.loseConnectionのおかげで切れてしまいます。そこでこれをコメントアウトし、つなぎっぱにしてふたつtelnetを立ち上げてつなげると、つながります。つまりちゃんと多重化されているんです。

これでは何もできないのでtransportやprotocolのメンバを調べます。本家のapi reference

2 Twisted解剖図鑑 を見ながら進めていきます。reactorが差し替えられる云々の話が出てきますが、ここが話が速い。今回はUIがない、デーモンを作るのであまり気にしなくていい。また、ここの例ではlineReceivedのなかでsendResponseしているが、このままではCometにならない。sendResponseに相当するメソッドを、別のタイミング(chat serverならbroadcastするタイミング)で呼んでやらないといけない。HTTP GETをなんらかの形で覚えておいて外部から指定されたタイミングで返す。そのために使えるAPIを探すことになる。

とりあえずはchat serverっぽい動きをするようにしてみた。connectionが切れたときにunregisterされていないのはご愛嬌。

#/usr/bin/python

# from
# http://omake.accense.com/wiki/Twisted%E3%81%AE%E7%9F%AD%E3%81%84%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E9%9B%86


from twisted.internet import reactor, protocol

host = 'localhost'
port = 3165


clients = []
class MyProtocol(protocol.Protocol):
def connectionLost(self, reason):
pass

def connectionMade(self):
clients.append(self)

def dataReceived(self, data):
print data
for c in clients:
c.sendMessge(data)

def sendMessge(self, msg):
self.transport.write(msg)

class TCPServer(protocol.ServerFactory):
def buildProtocol(self, addr):
return MyProtocol()

reactor.listenTCP(port, TCPServer())
reactor.run()


reactorに何か追加すればよいのだろう。listenTCPの代わりになにかメソッドを追加するか、もしくはほかのサーバと連携するための口としてTCPを使ってしまい、もうひとつProtocolを書く。その中でclientsをなめてsendMessageすればよい。

とりあえず、TCP version

#/usr/bin/python

from twisted.internet import reactor, protocol


clients = []

class Subscription(protocol.Protocol):
def connectionLost(self, reason):
pass

def connectionMade(self):
clients.append(self)

def dataReceived(self, data):
pass

def sendMessge(self, msg):
self.transport.write(msg)

class Subscriver(protocol.ServerFactory):
def buildProtocol(self, addr):
return Subscription()


class Publication(protocol.Protocol):
def connectionLost(self, reason):
pass

def connectionMade(self):
pass

def dataReceived(self, data):
for c in clients:
c.sendMessge(data)

def sendMessge(self, msg):
pass

class Publisher(protocol.ServerFactory):
def buildProtocol(self, addr):
return Publication()


reactor.listenTCP(3165, Subscriver())
reactor.listenTCP(3124, Publisher())
reactor.run()

0 件のコメント: