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()))
app
<!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>
templates/index.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()
app
<!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>
templates/index.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、双方可以进行互相通信了

 

posted @ 2018-08-05 16:24  争-渡  阅读(342)  评论(0)    收藏  举报