ページ

2010年10月26日

gevent的websocket生活

IE9での実装は見送られて悲しいwebsocketで遊んでいたのはもう、一年近く前のことになります。そのときに書いたチャットのサンプルコードですが、サーバサイドはgolangで書いていました。golangはとっても好きな言語なのですが、Python、特にgeventはどうなのかな?と思って調べてみました。単にネタがなくってwebsocketに走ったと言えなくもないです。ごめんなさい。

geventでwebsocketってどうするの?と。twistedであれば、かなり独自のコードを書いて独自の処理を追加しないと行けません。Python界隈ではwsgi全盛の今となってはそれはないよね!と。今時のPythonの人はwsgiのミドルウェアを使ってwebsocketをやるもんだぜ!えっ?geventはどうなって?Flaskでも動かしてやって、イベントループをgeventを使うようにして、monkey patchをあてれば、同期処理で動いてたwebsocketが非同期になって、C10K問題も解決だぜ、ベイビー。おしまい。

まあ、ことはそれほど単純じゃないですし、それだけだとつまらないので、geventでwebsocketを扱うgevet-websocketで書いてみます。昨日、Komodo Editを使うって宣言しておきながら、Emacsで書いています。はい。軟弱ものです。gevent-websockeはpip install gevent-websocketでインストールできます。

基本的にクライアントのコードは一年前とほぼ同じものです。ここにコードのすべてがあります。

from geventwebsocket.handler import WebSocketHandler
from gevent import pywsgi
import gevent

chat_clients = set()

def handle_chat(ws):
    chat_clients.add(ws)
    while True:
        message = ws.wait()
        if message is None:
            break
        for client in chat_clients:
            client.send(message)

    chat_clients.remove(ws)

def app(environ, start_response):
    path = environ["PATH_INFO"]
    if path == "/":
        start_response("200 OK", [("Content-Type", "text/html")])
        return open("chat.html").readlines()
    elif path == "/chat":
        handle_chat(environ["wsgi.websocket"])
    else:
        start_response("404 Not Found", [])
        return []

if __name__ == "__main__":
    server = pywsgi.WSGIServer(("", 5000), app, handler_class=WebSocketHandler)
    server.serve_forever()



geventには、wsgiとpywsgiという似たようなものが二ついます。一時pywsgiはobsoleteの警告が出ていたのに、最新版ではでなくなっています。二つの関係がよく分かりません。pywsgiのWSGIServerにWebSocket用のHandlerを渡します。このHanlderはクライアントがWebSocketとしての接続を要求してきたらWebSocketとして処理できるようになります。それ以外は通常のWSGIとして処理します。
WSGIのミドルウェアと違ってhandlerがenvironにwsgi.websocketにwebsocketのオブジェクトをセットします。
WebSocketで実際のロジックはhandle_chatのところです。めちゃくちゃ簡単ですね。golangのコードと大差ありません。

wsgiのインターフェースでこんな風に長時間の接続を処理するのは向いていないと思っていました。でも、計量スレッドのようなものたちの上で動かせば、そこそこ行けるんじゃないかと思い始めました。でもApacheのような人(同期IOで処理する人)がフロントにいるような環境だとやっぱり無理っぽいな〜、と。

もし、gevent-websocketのコードの説明を始めたら、それはネタがない証拠です。

でわでわ。

0 件のコメント: