上一篇文章:Python:Tornado 第三章:HTML5 WebSocket概念及應用:第一節:WebSocket概念
下一篇文章: Python:Tornado 第三章:HTML5 WebSocket概念及應用:第三節:客戶端程式設計
Tornado定義了tornado.websocket.WebSocketHandler類用於處理WebSocket連結的請求,應用開發者應該繼承該類並實現其中的open()、on_message()、on_close()函式。
- WebSocketHandler.open()函式:在一個新的WebSocket連結建立時,Tornado框架會呼叫此函式。在本函式中,開發者可以和在get()、post()等函式中一樣用get_argument()函式獲取客戶端提交的引數,以及用get_secure_cookie/set_secure_cookir等操作Cookie等。
- WebSocketHandler.on_message(message)函式:建立WebSocket連結後,當收到來自客戶端的訊息時,Tornado框架會呼叫本函式。通常,這是伺服器端WebSocket程式設計的核心函式,通過解析收到的訊息做出相應的處理。
- WebSocketHandler.on_close()函式:當WebSocket連結被關閉時,Tornado框架會呼叫本函式。在本函式中,可以通過訪問self.close_code和self.close_reason查詢關閉的原因。
除了這三個Tornado框架自動呼叫的入口函式,WebSocketHandler還提供了兩個開發者主動操作WebSocket函式。
- WebSocketHandler.write_message(message,binary=False)函式:用於向與本連結相對於的客戶端寫入訊息。
- WebSocketHandler.close(code=None,reason=None)函式:主動關閉WebSocket連結。其中的code和reason用於告訴客戶端連結被關閉的原因。引數code必須是一個數值,而reason是一個字串。
下面是持續為客戶端推送時間訊息的Tornado WebSocket程式:
import tornado.ioloop
import tornado.web
import tornado.websocket
from tornado import gen
from tornado.options import define,options,parse_command_line
import asyncio
clients=dict()#客戶端Session字典
class IndexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
@gen.coroutine
def get(self):
print("123")
self.render("index.html")
class MyWebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self, *args, **kwargs): #有新連結時被呼叫
self.id=self.get_argument("Id")
self.stream.set_nodelay(True)
clients[self.id]={"id":self.id,"object":self}#儲存Session到clients字典中
def on_message(self, message):#收到訊息時被呼叫
print("Client %s received a message:%s"%(self.id,message))
def on_close(self): #關閉連結時被呼叫
if self.id in clients:
del clients[self.id]
print("Client %s is closed"%(self.id))
def check_origin(self, origin):
return True
app=tornado.web.Application([
(r`/`,IndexHandler),
(r`/websocket`,MyWebSocketHandler),
])
import threading
import time
class SendThread(threading.Thread):
# 啟動單獨的執行緒執行此函式,每隔1秒向所有的客戶端推送當前時間
def run(self):
# tornado 5 中引入asyncio.set_event_loop,不然會報錯
asyncio.set_event_loop(asyncio.new_event_loop())
import datetime
while True:
for key in clients.keys():
msg = str(datetime.datetime.now())
clients[key]["object"].write_message(msg)
print("write to client %s:%s" % (key, msg))
time.sleep(1)
if __name__ == `__main__`:
#啟動推送時間執行緒
SendThread().start()
parse_command_line()
app.listen(8888)
#掛起執行
tornado.ioloop.IOLoop.instance().start()
解析上述程式碼如下:
- 定義了全域性變數字典clients,用於儲存所有與伺服器建立WebSocket連結的客戶端資訊。字典的鍵是客戶端id,值是一個由id與相應的WebSocketHandler例項構成的元組(Tuple)
- IndexHandler是一個普通的頁面處理器,用於向客戶端渲染主頁index.html。本頁面中包含了WebSocket的客戶端程式。
- MyWebSocketHandler是本例的核心處理器,繼承自tornado.web.WebSocketHandler。其中的open()函式將所有客戶端連結儲存到clients字典中;on_message()用於顯示客戶端發來的訊息;on_close()用於將已經關閉的WebSocket連結從clients字典中移除。
- 函式sendTime()執行在單獨的執行緒中,每隔1秒輪詢clients中的所有客戶端並通過MyWebSocketHandler.write_message()函式向客戶端推送時間訊息。
- 本例的tornado.web.Application例項中只配置了兩個路由,分別指向IndexHandler和MyWebSocketHandler,仍然由Tornado IOLoop啟動並執行。