前回の↓の記事の続きです。
今回はTornadoを使い、WebSocketともふれあいます。
TornadoとWebSocket
WebSocket
WebSocketはHTTPとは違うプロトコルで、HTML5から使えるようになったらしいです。
双方向通信が可能で、Ajaxとは違い、一度コネクションを貼るだけで全てのデータの送受信が可能になります。
Tornado
前回の記事でも書きましたが、TornadoはノンブロッキングなWebフレームワークです。
非同期処理をさせるならTornadoが向いてるので、今回はTornadoでやっていこうと考えました。
今回作るアプリ
今回作ろうと思うものはWebSocketを使ったチャットですが、なんかつまらないので、受信した日本語の文字を形態素解析し、文節ごとに空白を挟んでからみんなに送信するようなものにしたい思います。
コードを書く
こんな感じで書きました。
# -*- coding: utf-8 -*- import os import random from pypugjs.ext.tornado import patch_tornado import tornado.httpserver import tornado.ioloop from tornado import template import tornado.web import tornado.websocket from tornado.web import url patch_tornado() from janome.tokenizer import Tokenizer import json class IndexHandler(tornado.web.RequestHandler): def get(self): self.render("index.pug") class TokenizeHandler(tornado.websocket.WebSocketHandler): users = set() def open(self): self.users.add(self) print('Session opened by {}'.format(self.request.remote_ip)) def on_message(self, message): message = json.loads(message) t = Tokenizer() tokens = t.tokenize(message["text"]) message["text"] = "" for token in tokens: message["text"] += "{} ".format(token.surface) for user in self.users: user.write_message(message) def on_close(self): self.users.remove(self) print('Session closed by {}'.format(self.request.remote_ip)) class Application(tornado.web.Application): def __init__(self): BASE_DIR = os.path.dirname(os.path.abspath(__file__)) handlers = [ url(r'/', IndexHandler, name='index'), url(r'/tokenize', TokenizeHandler, name='tokenize'), ] settings = dict( template_path=os.path.join(BASE_DIR, 'templates'), static_path=os.path.join(BASE_DIR, 'static'), debug=True, ) tornado.web.Application.__init__(self, handlers, **settings) if __name__ == '__main__': app = Application() http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8000) tornado.ioloop.IOLoop.instance().start()
tornado.websocket.WebSocketHandler
を継承している、TokenizeHandler
が今回の主役です。
open
メソッドはコネクションが確立したときに発火されるもので、on_message
メソッドはクライアントからのメッセージ受信時、on_close
メソッドはコネクションが閉じられたときに発火されるものです。
ユーザーからのテキストの形態素解析には簡単に使用できて手軽だったJanomeを使用しました。
ハンドラーの中にusers
という集合を設け、コネクションが来たらそのコネクションを追加しています。
誰かの発言を受け取ったところで処理をし、集合の中身をfor文で回して全員にテキストを送っています。
そんなTokenizeHandler
を/tokenize
で待ち受けておくというコードになっています。
また、write_messages
メソッドなんですが、文字列でないものが渡るとjsonの形になおしてから送ってくれるようです。便利ですね。
これだけです。とても簡単に書くことが出来ました。
あとはこれをクライアント側で受け取るコードを書くのですが、今回は割愛します。あとでgithubのリポジトリを貼るので気になる方はそっちで見て下さい。
おわりに
今回のGithubリポジトリです。Helloworldは前回の分です。
とても簡単にWebSoketのサーバーを書くことが出来ました。
便利な上にきれいなコードになるTornadoですが、けっこういい印象を持つことが出来ました。
小規模なアプリ開発でもTornado使ってしまっていいんじゃないか?と思えるくらいいい感じです。
他にもTornadoにはログイン処理に関する機能だったり、ログだったり、多機能かつ高機能らしいです。
またいろいろ使ってみてもいいかなーと思えました。