2009年12月22日

apache+mod_pywebsocetを用いたliteなwebsocketsチャットサンプル



apache + mod_pywebsocketで web sockets のサーバーインストールまで出来ました

ここまで、来ると
せっかくなんだから、Web IFのGUIが欲しいなぁ
とか
echoだけだと寂しいから、チャットのサンプルが欲しいなぁ
とか思ってしまいます。てことで、作って見ました。

google code(subversion)にサンプルを置いておきましたので、
$ svn checkout http://html5clock.googlecode.com/svn/trunk/websocketsample somewhere
でチェックアウトして見てください。html が、Websocketsサーバーを使うためのクライアントhtml, pythonが apache+mod_pywebsocket用のチャットサンプルです。それぞれの環境に応じて、適当なディレクトリにそれぞれ置いて使って見てください。

まず、html/sample.htmlのほうから説明。(対象ブラウザはchrome4のみです)
websocketclientsample
resourceで接続するwebsocketのプログラムを指定して、"connect"を押し、メッセージを入力して"send"をクリックするだけのいたって簡単なWebアプリです。例えば、mod_pywebsocketのサンプルスクリプト "echo_wsh.py"を使うのであれば、resourceに"echo"を指定すればOKです。この場合は、"send"したメッセージと同じメッセージが”山びこ”として返ってきます。

ちなみに、mod_pywebsocketでは、_wsh.pyより前の部分が、接続するサーバーのリソース名になります。例えば、foo_wsh.pyであれば ws://somewhere/foo/でアクセスするといった具合です。

次にchatプログラムです。checkoutしたpythonディレクトリ内にある test_wsh.py を、mod_pywebsocketのルートディレクトリ配下(echo_wsh.pyを置いたのと同じディレクトリ。この例であれば /somewhere/websock_handlers/)に置き、12行目の file = '/somewhere/test'を適当なファイル名に変更後(apacheの起動ユーザーがwrite可能なディレクトリにしてください。あと、そのファイルを
$ touch /somewhere/test
で作成してください。

その後、先のsample.htmlでリソースを"test"にするとアクセス可能です。一見 echo と同じに見えますが、もう一つブラウザ(chrome4)を開いて同じURIにアクセスして使ってみると、チャットになっていることが分かると思います。

echo_wsh.pyを拡張する形でコーディングしましたが、ちょっと複雑なのでこのプログラムについては、簡単に説明します。

apacheにmod_pywebsocketを組み込むと、それぞれの接続ユーザーごとに異なるサーバープロセスが起動します。このため、各ユーザー(ブラウザ)から送信されたメッセージを、管理する仕組み(違うサーバープロセスで受信したメッセージを、他のプロセスに教えてあげる)が必要になります。模式図で書くと、下図のような感じ。
websocket0
この実現方法としてはいろいろ考えられますが、今回は最も簡単な方法ということでFileを使っています。

ユースケースは下記。
1. ユーザーからメッセージを受信したら、fileにそのメッセージを書き込みます。
2. それぞれのサーバープロセスは、fileが変更されたタイミングで最終行を読み込み、個々のユーザーにwebsocketsで送信します。
といった具合。

ソースコードは以下のようになります。なお、ファイルの変更検知の部分については、こちらのページを参考にさせていただきました。

書き換えたり、上手く動かない場合は、apacheのプロセスを再起動してください。そうしないと変更が反映されません。(はまりやすいところなので・・・)

from mod_pywebsocket import msgutil

import thread
import getopt
import os
import sys
import time

_GOODBYE_MESSAGE = 'Goodbye'
file = '/somewhere/test'

class tail():

        last_mtime = None

        def __init__(self, filename, delay, sock):
                self.filename = filename
                self.delay = delay
                self.sock = sock

        def run(self):
                while True:
                        time.sleep(self.delay)
                        stat = os.stat(self.filename)
                        
                        if stat.st_mtime != self.last_mtime:
                                self.last_mtime = stat.st_mtime
                                self.read()

        def read(self):
                try:
                        length = 0
                        f = open(self.filename, 'r')
                        for line in f:
                                length += 1

                        f.seek(0)
                        cnt = 0

                        for line in f:
                                cnt += 1
                                if cnt == length:
                                        msgutil.send_message(self.sock, line[:-1])
                        f.close
                except Exception:
                        if(f):
                                f.close

def web_socket_do_extra_handshake(request):
        pass  # Always accept.


def web_socket_transfer_data(request):
        attr = ()
        thread.start_new_thread(tail(file, 0.5, request).run, attr)
        while True:
                try:
                        line = msgutil.receive_message(request)
                
                        f = open(file, 'a')
                        f.write(line+"
")
                        os.fsync(f.fileno())
                        f.flush()
                        f.close

                        if line == _GOODBYE_MESSAGE:
                                return
                except Exception:
                        return


人気ブログランキングへ
kotesaki at 02:34│Comments(7)TrackBack(1)clip!html5 | websockets

トラックバックURL

この記事へのトラックバック

1. 【Web Sockets】Web Socketsサンプルチャット  [ JavaScript++かも日記 ]   2009年12月26日 01:54
html5-developers-jpで流れてた小松さんの pywebsocket版 Web Socketsサンプルチャットを別ドメインからテスト。Chrome 4 (v 4.0.249.0 +) が必須です。 http://jsgt.org/ws/sample.html http://bloga.jp/sample.html パケットみると、ヘッダのやりとりは、ちゃんと初回だけ...

この記事へのコメント

1. Posted by 高橋登史朗   2009年12月25日 22:38
小松さんすみません。トラックバック3本も送ってしまいました。
2. Posted by 管理人   2009年12月30日 18:07
TBありがとうございます!!余分な分、削除しておきました。
3. Posted by sacs longchamp   2012年10月30日 18:35
とか思ってしまいます。てことで、作って
4. Posted by natsuki   2012年11月14日 10:34
5
hello!" python mod_pywebsocket/standalone.py -p 8080 -d '/home/natsuki/chat/somewhere/html' -w '/home/natsuki/chat/somewhere/python' ";
browse "http://127.0.0.1:8080/wsclient/";
"connect">"connect succeed : test";
"send">"closed";
why does this happen?
5. Posted by cheap moncler jackets   2012年12月03日 23:19
合は、"send"したメッセージと同じメッセージが”山び
6. Posted by Guild wars 2 Gold   2013年04月11日 21:19
小松さんすみません。トラックバック3本も送ってしまいました。
7. Posted by hermes 新作 バッグ   2014年08月30日 18:24
http://www.loplopland.com/cgi-bin/blog/data/sales/hermes-jp-39.htmlエルメス バッグ
hermes 新作 バッグ http://www.loplopland.com/cgi-bin/blog/data/sales/hermes-jp-128.html

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔