一、什么是websocket?
websocket是html定义的一种标准的协议, 旨在解决浏览器与服务器之间的全双工通信,比如微信好友上线通知、新闻热点通知等,都可以通过websocket来实现服务器向客户端发送消息。
websocket能够解决Http+HTML在应用中的局限性。
二、基于tornado实现websocket通信
1.WebsocketHandler学习
WebsocketHandler是tornado.web框架下封装的处理websocket通信的类,继承WebsocketHandler类,能实现对Websocket消息的操作,WebsocketHandler的常用函数有:
1) WebSocketHandler.open()
  在一个新的WebSocket链接建立时,Tornado框架会调用此函数。在本函数中,我们可以和在get()、post()等函数中一样用get_argument()函数获取客户端提交的参数,以及用get_secure_cookie/set_secure_cookie操作Cookie等,如下:
self.stream.set_nodelay(True) : 官方解释: set the no-delay flag for this stream, 在一个数据包在发送中,往往会分为很多很小的消息,这就会导致在发送消息是出现200-500ms的延迟,通过设置set_nodelay(True)能够增大TCP连接时增大带宽以达到减小延时的目的,同时我们应该一个websocket连接一建立的时候去调用这个方法。
2) WebSocketHandler.on_message(message)
建立WebSocket链接后,当收到来自客户端的消息时,Tornado框架会调用本函数。通常,这是服务器端WebSocket编程的核心函数,通过解析收到的消息做出相应的处理。
3) WebSocketHandler.on_close()
当WebSocket链接被关闭时,Tornado框架会调用本函数。在本函数中,可以通过访问self.close_code和self.close_reason查询关闭的原因。
4)WebSocketHandler.write_message(message, binary=False)
用于向与本链接相对应的客户端写消息。
5)WebSocketHandler.close(code=None,reason=None)
主动关闭WebSocket链接。其中的code和reason用于告诉客户端链接被关闭的原因。参数code必须是一个数值,而reason是一个字符串。
2.基于tornado实现服务端给客户端持续推送时间
服务端server.py
import tornado.ioloop
import tornado.web
import tornado.websocket
from tornado import gen
from tornado.options import define, options, parse_command_line
define("port", default=8888, help="run on given port", type=int)
# 定义一个空的字典
clients = dict()
class IndexHandler(tornado.web.RequestHandler):
# 异步访问
@tornado.web.asynchronous
def get(self):
print("访问系统首页...")
self.render("index.html")
class MyWebSocketHandler(tornado.websocket.WebSocketHandler):
# 有新的连接时open()函数将会被调用,将客户端的连接统一放到clients
def open(self, *args, **kwargs):
self.id = self.get_argument("id")
self.stream.set_nodelay(True)
clients[self.id] = {"id": self.id, "object": self}
print(clients)
print("建立连接...")
# 客户收到消息将被调用
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
import threading
import time
import datetime
def send_time():
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)
app = tornado.web.Application([
(r"/", IndexHandler),
(r"/websocket", MyWebSocketHandler)
])
if __name__ == "__main__":
threading.Thread(target=send_time).start()
parse_command_line()
app.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
客户端index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>系统首页</title>
</head>
<body>
欢迎您!<br>
<a href="javascript:WebSocketTest()">启动websocket</a>
<div id="messages"></div>
</body>
<script type="text/javascript">
var message_editors=document.getElementById("messages")
function WebSocketTest(){
if ("WebSocket" in window){
message_editors.innerHTML="websocket is supported by windows"
var ws=new WebSocket("ws://localhost:8888/websocket?id=12345")
console.log(ws)
alert("启动websocket!")
ws.open=function(){
ws.send("message to send");
}
ws.onmessage=function(evt){
var recevied_msg=evt.data
message_editors.innerHTML=message_editors.innerHTML+"<br/>message is reveived:"+recevied_msg
}
ws.onclose=function(){
message_editors.innerHTML=message_editors.innerHTML+"<br/>connection is closed..."
}
}else{
message_editors.innerHTML="websocket not supported by your brower!"
alert("不支持websockt!")
}
}
</script>
</html>
测试以及结果
访问Localhost:8888, 点击启动websocket,观察控制台和浏览器页面信息
1)控制台打印信息:
2)点击启动websocket, 查看浏览器接收消息: