2012年11月29日 星期四

使用 python Tornado 實作 WebSocket 聊天室

 

早期網頁更新訊息必須 Refresh 整個頁面,這使得網頁互動效果有一定的限制在。後來 AJAX 的火紅,使得網頁的 UX 提升到了另一個境界。

但 AJAX 仍無法有效率的處理 Realtime 的訊息傳遞,最多只能做到 Realtime-like,畢竟仍是 client 主動,server 被動,若 server 有資料更新,client 也只能透過 polling 的方式來偵測資料是否有更新,而這不但 client 辛苦,server 更是得面臨大量的 garbage packet

只要瀏覽器支援,其實透過 WebSocket 來處理是更理想的。WebScoket 跟傳統 socket 在使用上非常相似,都是由 client 主動連線,並在正常情況下可保持連線,使得 server 可直接將訊息送到「連接中」的 client

 

程式碼如下

Server side

chatroom.py

import tornado.ioloop
import tornado.web
from tornado import websocket
 
clients = []
 
class ChatRoom(websocket.WebSocketHandler):
    def open(self):
        clients.append(self)
    
    def on_close(self):
        clients.remove(self)
    
    def on_message(self, message):
        for client in clients:
            client.write_message(message)
 
application = tornado.web.Application([
    (r"/", ChatRoom),
])
 
if __name__ == "__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()

 

Client side

chatroom.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Chat Room</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script language="javascript" type="text/javascript">
$(document).ready(function () {
    var socket = new WebSocket("ws://localhost:8000/");
    socket.onmessage = function(event) {
        $("#message").append("<div>" + event.data + "</div>");
    }
    
    $("#send").click(function() {
        socket.send($("#text").val());
        $("#text").val("").select();
    });
});
</script>
</head>
<body>
<div id="message"></div>
<textarea id="text"></textarea>
<input type="button" id="send" value="send" />
</body>
</html>

 

安裝 Tornado 不多提,實際執行結果如下:

執行 chatroom.py

SNAGHTML2afaaf

 

多開 chatroom.html,就可以進行聊天了

image