tornado - 原生websocket

WebSocket概念

传统的HTTP与HTML技术使用客户端主动向服务器发送请求并获得回复的应用场景。但随着即时通信需求的增多,这样的通信不能满足要求。

websocket与普通的socket通信类似,打破原来的request和response一对一的通信模型,同时打破了服务器被动接收客户端请求的应用场景。

websocket是基于HTTP的协议。是用http协议规定传递。协议规定了浏览器和服务端创建连接之后,不断开,保持连接。相互之间可以基于连接进行主动的收发消息,即时通信。

服务端编程

Tornado定义了WebSocketHandler类用于处理websocket连接的请求,可以继承该类实现其中的open()on_message()on_close()函数。

  • open():在一个新的连接建立时,会调用此函数,可以获取客户端提交的参数,以及可以操作cookie等。
  • on_message():建立连接后,当收到来自客户端的请求时,会调用此函数。可以通过解析接收到的信息做相应的处理。
  • on_close():当连接被关闭时,会调用此函数。再此函数中,可以通过访问self.close_codeself.close_reason查询关闭的原因。

除了上述3个字段调用的函数外,还提供了2个开发者主动操作websocket的函数。

  • write_message(message,binary=Flase): 用于向与本链接相对于的客户端写消息。
  • close(code=None,reaon=None): 主动关闭连接,其中code和reason用于告诉客户端连接被关闭的原因。code参数必须是一个数值,而reason是一个字符串。
import tornado.ioloop
import tornado.web
import tornado.websocket

from tornado.options import define, options, parse_command_line

define("port", default=8888, help="run on the given port", type=int)

clients = dict()

class IndexHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        self.render("index.html")
        
class MyWebSocketHandler(tornado.websocket.WebSocketHandler):
    
    # 有新链接时被调用执行
    def open(self, *args):
        self.id = self.get_argument("id")
        self.stream.set_nodelay(True)
        client[self.id] = {"id": self.id, "object": self}	# 保存session到字典中
        
     # 收到消息时被调用
    def on_message(self, message):
        print("客户端%s发来一条消息: %s"%(self.id, message))
    
    # 关闭链接时被调用
    def on_close(self):
        if self.id in clients:
            del clients(self.id)
            print("客户端%s断开连接"%(self.id))
            
    def check_origin(self, origin):
        return True

app = tornado.web.Application([
    (r'/', IndexHandler),
    (r'/websocket', MyWebSocketHandler)
])

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("发送给客户端%s:%s"%(key, msg))
        time.sleep(1)
 
if __name__=='__main__':
    
    threading.Thread(target=send_time).start()	# 启动推送时间的线程
    parse_command_line()
    app.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

客户端编程

由于websocket时HTML5的标准之一,所有主流浏览器的web客户端编程语言JavaScript可以支持websocket的客户端编程。

JavaScript初始化websocket对象:

var socket = new WebSocket(url);

在代码中只需给websocket的构造函数传入URL地址,比如http://xxx.com。可以为该对象的如下事件指定处理函数以响应它们。

  • WebSocket.onopen: WebSocket连接建立时调用。
  • WebSocket.onmessage: 接收到来自服务器的消息时调用。
  • WebSocket.onerror: 通信错误时调用。
  • WebSocket.onclose: 与服务器连接断开时调用。

还可以主动进行操作:

  • WebSocket.send(data): 向服务器发送消息。
  • WebSocket.close: 主动关闭连接。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket</title>
</head>
<body>
    <a href="javascript:WebSocketTest()">Run WebSocket</a>
    
	<div id="msg" style="height:200px; background:black; color:white;"></div>
</body>
<script type="text/javascript">
	var messageContainer = document.getElementById("msg");
    
    function WebSocketTest(){
        if ("Websocket" in window){
            messageContainer.innerHTML = "Websocket is supported by your Browser!";
            var ws = new WebSocket("ws://localhost:8888/websocket?id=12");
            
            ws.onopen = function(){
                ws.send("Message to send");
            };
           	ws.onmessage = function(evt){
                var recv_msg = evt.data;
                messageContainer.innerHTML = messageContainer.innerHTML + "<br/>Message is received:" + recv_msg;
            };
            ws.onclose = function(){
            	messageContainer.innerHTML = messageContainer.innerHTML + "<br/>Connection is closed...";
                
            };
        }eles{
            messageContainer.innerHTML = "WebSocket Not supported by your Browser!";
        }
    }
</script>
</html>

上述代码解析:

  • Run WebSocket连接用于让用户启动Websocket;另一个id=msg的div标签用于显示服务器端传来的消息。
  • 使用JavaScript语句if ("Websocket" in window){}可以判断当前浏览器是否支持websocket对象。
  • 如果支持websocket对象,则连接服务器ws://localhost:8888/websocket,并且传入参数 id。然后通过websocket的处理函数,进行消息的展示。onopen事件向服务器发送消息。
posted @ 2020-08-27 13:01  SensorError  阅读(338)  评论(0编辑  收藏  举报