WebSocket使用及原理
1、WebSocket
1.1、关于WebSocket
WebSocket协议是基于TCP的一种新的协议。WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与服务器全双工(full-duplex)通信。其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信。
1.2、安装依赖模块
# Flask pip3 install gevent-websocket # Django pip3 install channel # torando # 天生支持
1.3、基于Flask简单使用WebSocket

from flask import Flask, Request, render_template, request, session, redirect from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer import json import uuid import time app = Flask(__name__) # http://127.0.0.1:5000/index @app.route('/index') def index(): return render_template('index.html') # http://127.0.0.1:5000/message @app.route('/message') def message(): # 如果是websocket协议,environ中会有wsgi.websocket此值 ws = request.environ.get('wsgi.websocket') if not ws: return 'HTTP' print(ws) while True: # 等待用户端发来数据,并接受 # message = ws.receive() time.sleep(2) # print(message) ws.send(str(time.time()))

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>首页</h1> </body> <script> <!--应用websocket协议方法--> var ws = new WebSocket('ws://127.0.0.1:5000/message'); ws.onmessage = function (event) { /* 服务器端向客户端发送数据时,自动执行 */ var response = event.data; // event.data:服务端返回的值 console.log(response) }; ws.send('你好') </script> </html>
1.4、基于Flask进行投票模拟

# 模拟投票 from flask import Flask, Request, render_template, request, session, redirect from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer import json app = Flask(__name__) app.secret_key = 'xfsdfqd' USERS = { '1': {'name': '钢球', 'count': 0}, '2': {'name': '飞机', 'count': 0}, '3': {'name': '大炮', 'count': 0} } # http://127.0.0.1:5000/index @app.route('/index') def index(): """ 主界面显示 :return: """ return render_template('index.html', user=USERS) # http://127.0.0.1:5000/message WEBSOCKET_LIST = [] @app.route('/message') def message(): """ 如果走的是websocket处理方法 :return: 用户的id与票数 """ # 如果是websocket协议,environ中会有wsgi.websocket此值 ws = request.environ.get('wsgi.websocket') if not ws: return 'HTTP' print(ws) WEBSOCKET_LIST.append(ws) while True: # 等待用户端发来数据,并接受 cid = ws.receive() print(cid) # 如果前端关闭了投票捕捉到cid = None if not cid: WEBSOCKET_LIST.remove(ws) ws.close() break old = USERS[cid]['count'] new = old + 1 USERS[cid]['count'] = new for client in WEBSOCKET_LIST: # 为每一个服务端更新结果 ws.send(json.dumps({"cid": cid, 'count': new})) if __name__ == '__main__': # app.run() # 理解如果遇到HTTP协议可以交给Flask内的函数来处理,如果遇到了WebSocket协议交给handler_class处理 http_server = WSGIServer(('127.0.0.1', 5000), app, handler_class=WebSocketHandler) # 运行期这个系统 http_server.serve_forever()

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>首页</h1> <ul> {% for i, j in user.items() %} <li onclick="vote({{i}})" id='id_{{i}}'>{{j.name}}<span>{{j.count}}</span></li> {% endfor %} </ul> </body> <script src='http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js'></script> <script> <!--应用websocket协议方法--> var ws = new WebSocket('ws://127.0.0.1:5000/message'); ws.onmessage = function (event) { /* 服务器端向客户端发送数据时,自动执行 */ var response = event.data; // event.data:服务端返回的值 var responses = JSON.parse(response); // 后端序列化了需要反序列化 $('#id_' + responses.cid).find('span').text(responses.count); }; function vote(cid) { ws.send(cid) } </script> </html>
1.5、WebSocket底层原理
WebSocket原理: 1、服务端运行,等待客户端链接 2、客户端来连接,服务端同意 3、客户端理解发送一个‘握手信息’ Upgrade: websocket Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cache-Control: no-cache Connection: Upgrade Cookie: session=cced7c54-6edd-47d2-b72f-428ab0b86870; csrftoken=RRW1dvunB5wLrTu3boh9VrNVep8gQdxBRmEQDVqcyRujMzUb2upz8qr4ZUtoU0BB Host: 127.0.0.1:5000 Origin: http://127.0.0.1:5000 Pragma: no-cache Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Key: CGQgHOr2/rrPb9InneR6HQ== ########### 这里 ############## Sec-WebSocket-Version: 13 Upgrade: websocket User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 4、服务端接收握手信息后需要对数据进行加密,给客户端返回: 4.1、连接 CGQgHOr2/rrPb9InneR6HQ== + magic_string 4.2、sh1加密 4.3、base64加密 4.4、将加密后的结果返回给客户端 response_tp1 = "HTTP/1.1 101 Switching Protocols" "Upgrade: websocket" "Connection: Upgrade" "Sec-WebSocket-Accept: 加密之后的结果" 5、双方可以进行互相通信了