2015年8月25日

Tornado 教學 (10) - 使用 WebSocket 建立聊天室 ( Create a chat app using WebSocket with Tornado Web Framework )

經過前面幾篇文章,相信對於 Tornado 的架構與特性都有些理解了。接下來,我們將開始利用 Tornado 與 WebSocket 來建立一個聊天室。( 其他 Tornado 相關教學可以參考本篇整理 )



暸解 WebSocketHandler:
Tornado 提供了一個 WebSocket 模組,我們將透過其中的 WebSocketHandler 來與 WebSocket 互動,有三個函式需要稍微暸解:open()on_message( )on_close( )。當 Client 端開啟一個 WebSocket 時,open( ) 將會被執行,on_message( ) 而是接收到訊息時會執行,on_close( ) 則是在連線關閉時會執行。


實作 WebSocketHandler:
首先,我們建立一個名為 server.py 的檔案,接著在裡面建立我們 Server 端的內容:
#!/usr/bin/env/ python
import os
from tornado import web, ioloop, websocket
from tornado.options import define, options

define("ip", default="your.ip")
define("port", default=8888)

# 此物件將記錄並管理所有連線
class ChatManager(object):
    users = []
    @classmethod
    def add_user(cls, websocket):
        cls.users.append(websocket)

    @classmethod
    def remove_user(cls, websocket):
        cls.users.remove(websocket)

# 輸出聊天室 UI 畫面
class Chat(web.RequestHandler):
    def get(self):
        self.render("chat.html")

# 利用 WebSocketHandler 來與 Client 端互動
class Socket(websocket.WebSocketHandler):
    def open(self):
        # 完成連線,將此 WebSocket 儲存
        print ' [x] connected.'
        ChatManager.add_user(self)

    def on_close(self):
        # 連線結束,將此 WebSocket 移除
        print ' [x] disconnected.'
        ChatManager.remove_user(self)

    def on_message(self, message):
        # 當有訊息進來時,將此訊息發送給其他 WebSocket
        print ' [x] send message.'
        for user in ChatManager.users:
            user.write_message(message)

# 相關設定參數
settings = dict(
    debug=True,
    autoreload=True,
    compiled_template_cache=False,
    static_path=os.path.join(os.path.dirname(__file__), "static"),
    template_path=os.path.join(os.path.dirname(__file__), "templates")
)

class Application(web.Application):
    def __init__(self):
        handlers = [
            (r"/", Chat),
            (r"/socket", Socket)
        ]
        web.Application.__init__(self, handlers, **settings)

def main():
    options.parse_command_line()
    app = Application()
    app.listen(options.port, options.ip)
    ioloop.IOLoop.current().start()

if __name__ == "__main__":
    main()


實作 WebSocket:
Client 端的實作,主要是使用 HTML5 提供的方式,所以不需要額外的套件,只需要支援 WebSocket 的瀏覽器即可。建立檔案 templates/chat.html。關於 WebSocket 更詳細資訊請參考 HTML5 文件,這邊就不再贅述了,直接看程式內容:
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .msg-box {
            border: 1px solid #ddd;
            width: 500px; height: 300px;
            overflow-y: scroll;
        }
    </style>
</head>
<body>
    <!-- UI -->
    <input id="msg-input" type="text" value=""/>
    <input id="msg-btn" type="button" value="Send"/><br/><br/>
    <!-- Messages -->
    <div id="msg-box" class="msg-box"></div>
    <script src="/static/jquery-1.11.3.js"></script>
    <script>
        var chatObj = {
            host: location.host,
            socket: null,
            // 開啟一個 WebSocket 連線,並設定相關動作
            init: function(){
                var url = "ws://" + chatObj.host + "/socket";
                chatObj.socket = new WebSocket(url);
                chatObj.socket.onmessage = function(event){
                    chatObj.showMsg(event.data);
                },
                chatObj.socket.onclose = function(event){
                    console.log("on close");
                },
                chatObj.socket.onerror = function(event){
                    console.log("on error");
                }
            },
            // 發送訊息至 Server 端
            sendMsg: function(){
                var msg_input = $("#msg-input")
                chatObj.socket.send(msg_input.val());
                msg_input.val("").select();
            },
            // 顯示訊息
            showMsg: function(message){
                $("#msg-box").append(message + "<br/>");
            }
        };

        $(function(){
            var btn = $("#msg-btn");
            // 綁定按鈕 click 時發送訊息
            btn.click(function(){
                chatObj.sendMsg();
                return false;
            });
            $("#msg-input").select();
            chatObj.init();
        });
    </script>
</body>
</html>
最後,專案檔案的配置如下:
├── Tornado-websocket
    ├── server.py
    ├── static
    │   └── jquery-1.11.3.js
    └── templates
        └── chat.html
以上工作都完成後,開啟多個瀏覽器分頁並連至 http://your-ip:8888/,分別的在不同的地方輸入文字訊息,就可以看到其他頁面自動同步的狀況了。


Environment :
  ・ Arch Linux
  ・ Python 2.7

Reference :
  ・ Tornado


熱門文章