読者です 読者をやめる 読者になる 読者になる

ami_GS's diary

情報系大学院生の備忘録。ネットワークの勉強にハマっています。

TornadoでWebSocketやってみた

Tornado WebSocket Python

TwistedでUDP使っていると、
「やっぱり時代の流れ的にWebSocketでやった方が便利かなぁ」
と思ったので触ってみた。

WebSocketはHTTPとは違った独自のプロトコルなので、GET,POST等のメソッドは持ちません
プログラムで主に使うのは、

  • on_message(データを受け取る)
  • write_message(データを送る)

となります。


ローカルで文字データを送るだけのプログラムにすると一瞬で処理が終わってしまうので、コールバックを使って遅延を発生させます。

サーバ側

import time
import tornado.ioloop
import tornado.web
import tornado.websocket
from tornado.ioloop import PeriodicCallback

from tornado.options import define, options, parse_command_line

define("port", default = 8080, help = "run on the given port", type = int)

class IndexHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        self.render("index.html")

class SendWebSocket(tornado.websocket.WebSocketHandler):
    #on_message -> receive data
    #write_message -> send data

    #index.htmlでコネクションが確保されると呼び出される
    def open(self):
        self.i = 0
        self.callback = PeriodicCallback(self._send_message, 400) #遅延用コールバック
        self.callback.start()
        print "WebSocket opened" 

    #クライアントからメッセージが送られてくると呼び出される
    def on_message(self, message):
        print message

    #コールバックスタートで呼び出しが始まる
    def _send_message(self):
        self.i += 1
        self.write_message(str(self.i))

    #ページが閉じ、コネクションが切れる事で呼び出し
    def on_close(self):
        self.callback.stop()
        print "WebSocket closed"

app = tornado.web.Application([
    (r"/", IndexHandler),
    (r"/ws", SendWebSocket),
])

if __name__ == "__main__":
    parse_command_line()
    app.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

Tornadoはシングルスレッドかつノンブロッキングで動作するためPeriodicCallbackで遅延を作っています。
time.sleep(400)等を使うとエラーが出る(と思う)のでやめましょう。

クライアント側

index.html

<html>
  <head>
    <title></title>
    <script language="javascript">
      var ws = new WebSocket("ws://localhost:8080/ws");
      ws.onopen = function() {
       ws.send("Hello, world"); 
      };
      ws.onmessage = function (evt) {
	   document.write("<strong>" + evt.data + "</strong>");
      };
    </script>
  </head>
  <body>
  </body>
</html>

使う

まずはサーバ側を起動し、ブラウザから 127.0.0.1:8080 に接続すると、最初はhttpでindex.htmlを呼び出し、それを読む事でwebsocketのコネクションが確立されます。
この例だと、ブラウザの左上から 1234567・・・・・と出てきます。
ページの読み込み無しに文字が書かれていくのでwebsocketっぽいのがわかる…かな…(javascriptでかけちゃうんだよなぁ)



まとめ

  • とりあえず使う事はできた。
  • 次は動画を送ってブラウザから見れるLive Stream的なのを作ろう