Flask - WebSocket

目录

  • Flask - WebSocket
    • WebSocket介绍
    • 基于WebSocket的群聊实例
    • 基于WebSocket的单聊实例

Flask - WebSocket

WebSocket介绍

概念:

是一套协议,协议规定了:

  - 连接时需要握手

  - 发送数据进行加密

  - 连接之后不断开

意义:

  实现长轮询等操作

框架支持

  • flask,gevent-websocket

  • django,channel

  • torando框架自带

应用场景:

实时响应页面时,可以使用websocket。

缺点:

兼容性比较差,版本较低的IE无法支持

使用方法:

geventWebsocket (第三方包)

导入

from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from geventwebsocket.websocket import WebSocket  # 做语法提示

 

启动

Flask 的启动的地方改成这样即可以支持 websocket ,同时并不会覆盖 http ,两者并存

if __name__ == '__main__':
    http_server = WSGIServer(('0.0.0.0', 5000), app, handler_class=WebSocketHandler)
    http_server.serve_forever()

注意: 端口要一致,不要运行Flask项目, 正常情况下启动后,处于监听状态.

后端操作

ws = request.environ.get('wsgi.websocket')  # 要拿到websocket 的标识才可以操作msg = ws.receive() # 从客户端接收消息ws.send("你好啊") # 向客户端发送消息

前端操作

var ws = new WebSocket('ws://127.0.0.1:5000/message')    // 不定义的话默认就是 HTTP,定义后往指定的url 发起 websocket 链接请求
ws.onmessage = function (event) {  // 服务器端向客户端发送数据时,自动执行
    var response = JSON.parse(event.data);    // 接收服务端的数据
};ws.send("你好呀")   // 向服务端发送消息

基于WebSocket的群聊实例

py文件中

 

import json

from flask import Flask, request, render_template

from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from geventwebsocket.websocket import WebSocket  # 做语法提示

# user_list = []

user_dict = {}

app = Flask(__name__)
@app.route("/ws/<username>")
def my_ws(username):
    # print(request.environ)
    user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
    user_dict[username] = user_socket
    print(user_dict)
    while 1:
        msg = user_socket.receive() # 等待客户端发送的数据
        u_msg = {"from_user":username,"chat":msg}
        for uname,usocket in user_dict.items(): # type:WebSocket
            usocket.send(json.dumps(u_msg))

        # msg = json.loads(msg)
        # print(msg,type(msg))
        # user_socket.send(json.dumps(msg))

@app.route("/webchat")
def webchat():
    return render_template("public_chat.html")


if __name__ == '__main__':
    # app.run("0.0.0.0",9527)
    server = WSGIServer(("0.0.0.0", 9527), app, handler_class=WebSocketHandler)
    server.serve_forever()

 

 

 

在.html 文件中

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>你的名字:<input type="text" id="username">
    <button onclick="open_ws()">登录聊天室</button>
</p>

<p>消息内容:<input type="text" id="message">
    <button onclick="send_msg()">发送消息</button>
</p>
<div id="chat_list">

</div>

</body>
<script type="application/javascript">

    var ws = null;
    function open_ws() {
        var username = document.getElementById("username").value;
        ws = new WebSocket("ws://192.168.16.232:9527/ws/"+username);
        ws.onopen = function () {
            alert("欢迎登录");
        };
        ws.onmessage = function (eventMessage) {
            var chat = JSON.parse(eventMessage.data);
            var p = document.createElement("p");
            p.innerText = chat.from_user + ":" + chat.chat;
            document.getElementById("chat_list").appendChild(p);
        };
    }

    function send_msg() {
        var msg = document.getElementById("message").value;
        ws.send(msg);
    }
</script>
</html>

 

基于WebSocket的单聊实例

在py文件中

 

import json

from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from geventwebsocket.websocket import WebSocket
from geventwebsocket.exceptions import WebSocketError

from flask import Flask,render_template,request

app = Flask(__name__)

user_socket_dict = {}

@app.route("/my_app")        #
def my_app():
    return render_template("my_app.html")

@app.route("/my_ws/<username>")
def my_ws(username):
    user_socket = request.environ.get("wsgi.websocket") #
    user_socket_dict[username] = user_socket
    print(len(user_socket_dict),user_socket_dict)
    while 1:
        try:
            msg = user_socket.receive() # 阻塞等待消息数据   #⑥
            print(msg,type(msg))
            msg_dict = json.loads(msg)
            # msg = {from_user:alexDSB,to_user:YWB,messge:"dsb"}
            to_user = msg_dict.get("to_user")
            to_user_socket = user_socket_dict.get(to_user)
            to_user_socket.send(msg)
            # user_socket_dict.get(msg.get(to_user) == "YWB").send(msg)
        except WebSocketError:
            user_socket_dict.pop(username)
            return "good bye"


if __name__ == '__main__':
    # app.run()
    http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
    http_serv.serve_forever()

 

在 .html 文件中

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
你的名字:<input type="text" id="nickname">
<button onclick="open_chat()">登录聊天室</button>
<p>发送至<input type="text" id="to_user"></p>
消息<input type="text" id="message">
<button onclick="send_message()">发送</button>
<div id="chat_list">

</div>
</body>
<script type="application/javascript">
    var ws = null;

    function open_chat() {
        var nickname = document.getElementById("nickname").value;
        ws = new WebSocket("ws://192.168.14.200:9527/my_ws/" + nickname);   # ②
        ws.onopen = function () {                     # 打开时的事件
            alert(nickname + "!欢迎登录对骂平台!");
        };
        ws.onmessage = function (eventMessage) {      # 监听有消息来时    # ⑦
            // document.getElementById("chat_list").innerHTML += "<p>" + eventMessage.data + "</p>";

            console.log(eventMessage.data);
            var chat = JSON.parse(eventMessage.data);
            var p = document.createElement("p");
            p.style.cssText = "width: 250px;text-align: left";
            p.innerText = chat.from_user + "->" + chat.message;
            document.getElementById("chat_list").appendChild(p);
        };
        ws.onclose = function () {                  # 关闭时的事件
            //断开重连机制
            console.log("连接断开了完全懵逼了");
        };
    }

    function send_message() {       #④
        var message = document.getElementById("message").value;
        var from_user = document.getElementById("nickname").value;
        var to_user = document.getElementById("to_user").value;
        var send_str = {
            from_user: from_user,
            to_user: to_user,
            message: message
        };
        ws.send(JSON.stringify(send_str));

        var p = document.createElement("p");
        p.style.cssText = "width: 250px;text-align: right";
        p.innerText = send_str.message + "<-我";
        document.getElementById("chat_list").appendChild(p);
    }

</script>
</html>

 

websocket 工作原理

 1.握手原理

①  对  sec-websocket-key   和   魔法字符串 magic_string  
  进行双重加密(sha1 和 base64)

②  和 客户端计算出的值进行比较

在 .py 文件中:

import socket, base64, hashlib

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1', 9527))
sock.listen(5)
# 获取客户端socket对象
conn, address = sock.accept() # 阻塞
# 获取客户端的【握手】信息
data = conn.recv(1024)
print(data)

"""
b'GET / HTTP/1.1\r\n
Host: 127.0.0.1:9527\r\n
Connection: Upgrade\r\n
Pragma: no-cache\r\n
Cache-Control: no-cache\r\n
Upgrade: websocket\r\n
Origin: http://localhost:63342\r\n
Sec-WebSocket-Version: 13\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9\r\n
Sec-WebSocket-Key: 176bkom1UAtHfS7MUYCwlQ==\r\n
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n'
"""
# 1.转字符串 切片
# 2.转字符串 正则
# 3.转字符串 split("\r\n") - [] for []

#
#
def get_headers(data):
    header_dict = {}
    header_str = data.decode("utf8")
    for i in header_str.split("\r\n"):
        if str(i).startswith("Sec-WebSocket-Key"):
            header_dict["Sec-WebSocket-Key"] = i.split(":")[1].strip()

    return header_dict

headers = get_headers(data)  # 提取请求头信息
# # 对请求头中的sec-websocket-key进行加密
swk = headers['Sec-WebSocket-Key']
# Websocket 中的魔法字符串 magic_string
magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
value = swk + magic_string
# 176bkom1UAtHfS7MUYCwlQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
# ZWHsGUn8ogDGd+JYzQunlQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
# dFRV9m2/6PWawNWYUkRHDw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
print(value)
print(ac)
# b'PIj4+UWLuqcpcTZcMnnu9Ik6rSQ='
# b'iZFEC+HI/NqNp5g2BoENbywWBLA='
# b'LXO3G84XmpR7crmJcZFaLPUDVHU='

response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
               "Upgrade:websocket\r\n" \
               "Connection: Upgrade\r\n" \
               "Sec-WebSocket-Accept: %s\r\n" \
               "WebSocket-Location: ws://127.0.0.1:9527\r\n\r\n"

response_str = response_tpl % (ac.decode('utf-8'))
# 响应【握手】信息
conn.send(response_str.encode("utf8"))

while True:
    msg = conn.recv(8096)
    print(msg)
    import websocket加密
    conn.send(websocket加密.res())
# # magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11

在 .html文件中:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script type="application/javascript">
    var ws = new WebSocket("ws://127.0.0.1:9527");
    ws.onmessage = function (data) {
        console.log(data.data);

    }
</script>
</html>

2.解密原理

# Websocket 加密 解密 3种情况
# 校验位 : 由websocket加密字符串的第二个字节与127期开始进行  与 位运算
# 校验位 == 127
# 校验位 == 126
# 校验位 <= 125
与 位运算: (有0就是0)
    01111111  ==  1字节  ==  127
    10001100  ==  1字节  ==  140
运算 00001100  ==  1字节  ==  12
    
<=125:
    01111111  127
    10011111  159
    00011111  31
 
==126:   
    01111111  127
    11111110  254
    01111110  126
 
==127:   
    01111111  127
    11111111  255
    01111111  127
异 或运算 (有1就是1)
    01111111  127
    10011111  159
    11111111  255
    
    01001101
    10000101
    11001101
# b'\x81\x83\xceH\xb6\x85\xffz\x85'

hashstr = b'\x81\x8c\xc2J\xb3\x0c\xaa/\xdf`\xadj\xc4c\xb0&\xd7-'
# b'\x81    \x8c    \xc2J\xb3\x0c\xaa/\xdf`\xadj\xc4c\xb0&\xd7-'
ssss = b'\x81\xfe\x0bp\x8fF\xa1\xa3j\xc3)F7\xdbD+\x14\xa2\x199i\xda\x0bF\x02\xccI#\x03\xa2\x19\x0ef\xc72F;\xefG\r\r\xa9\x1d/k\xfd+F+\xefE\x1b\x04\xa2\x19*j\xce\'L3\xcaF8\x05\xa3\x16=h\xd0\x13F3\xccN\x1f\x03\xa0\x0c\x07g\xe9;F\x02\xf7G#*\xa3\x0c;k\xfc\x00G6\xcdF\x04\x04\xa2\x18<l\xc6#D\x0b\xf0E\x1d\x02\xa3,\x08k\xff*K\x08\xe5E\x1b\x02\xa0&+k\xfc/F\t\xc3N\x1f\x03\xa3\x1e\x03j\xf96G6\xcdD\x00$\xa3\x1e;g\xfc\nG5\xc8D\x07\x19\xae!&`\xfa-D\x14\xd0I\x1c2\xa3$+j\xfe<G6\xcdG\r\x05\xaf $`\xfa-E#\xf4G)*\xa2\x18(k\xfc/J\x16\xddE\x1b\x04\xa2\x18<l\xc6#K \xdcD\r\x13\xa3\x1d#j\xfa\x01F\x13\xe5D3#\xa9\x1d/k\xfd\x04F\n\xcfD&\x07\xa3\x19>f\xc76F1\xf1N\x1f\x03\xa0 \x01j\xfa9F0\xd1D\x00$\xa2\x18(i\xf65L3\xcaE\x1b\x02\xa3\x0f?j\xe0%K\x08\xecI,=\xae7\'`\xfa-G6\xcdI\x14 \xa2\x18<`\xfa-F\n\xceD\x1b\x12\xa3)8k\xfe;E\x13\xecD.\x05\xae!/k\xfe\x0cJ\x0e\xd5D\x17&\xa0\x0f!`\xfa-G4\xccD\x07&\xa2\x19(k\xfe(F\x07\xc0N\x1f\x03\xa1:)j\xf1?D\x19\xf4D\x1f\x05\xa9\x1d/i\xeb\x05K \xdcD.>\xa0!\x06j\xeb9G5\xe7E\x1a\x04\xa1\x06(k\xff>@\x0f\xc4F\'9\xa2\x1f.j\xcb\nG6\xcdI$,\xa2\x19.i\xc1)G5\xc8D%\n\xa9\x1d/j\xf9\x01F0\xd1E\x1a\x04\xa3\x02\x08j\xf99K5\xedE\x19\x01\xa3\x055g\xc6$L3\xcaF8\x19\xae\x1e\x1ej\xc3)F7\xdbE\x1a\x04\xa0\x0f)f\xc7&L3\xcaG\x0f=\xa0+\x06k\xff*G5\xc8H:\x14\xa2\x19(k\xff>@\x0f\xc4I\x0c\x15\xa3\x0f?j\xfa!F3\xe6D?,\xa31\x0fh\xc2\x17G1\xcbD\x1f\x1a\xa37\x18j\xe2\x10F\x02\xedE\x1a\x04\xae&\x00k\xfe,E\x08\xceE\x19\x01\xa3\'&`\xfa-F0\xe6D\x1c\x18\xa2\x18(j\xe5\nF0\xdeI\x19$\xa2\x1b-j\xe27K\x0f\xc3N\x1f\x03\xa1:5g\xf9\x1cF\n\xceD\x1b\x12\xa2\x18(i\xe8+J\x0e\xc1N\x1f\x03\xa0\r\x11i\xcc\x04G6\xcdE\x19\x01\xaf88k\xfe*G6\xd9B#\r\xae\x0e9j\xe8=F3\xc6D\x1f/\xa3=\x00j\xd6\rL3\xcaE\x18*\xa3$*j\xc3)F7\xdbH"\x18\xa3\x1f\x14`\xfa-E\x0e\xe4D\x1f\x17\xa3\x1e4j\xe5\nG6\xcdG\x13\x1b\xa9\x1d/k\xfe,F!\xdaD\x05\x0b\xae&\tg\xc9\x13K\x19\xc2N\x1f\x03\xa3\x1d6j\xd0\x1aF+\xf7E\x1a\x06\xa9\x1d/k\xfd\x04F.\xd8D\x1c/\xae\x11,k\xff*K8\xe9E\x1a\x10\xa9\x1d/`\xfa-G7\xcbD\r\x13\xa3\x07\'g\xc1\x0bK\x00\xf4I5\x0b\xa9\x1d/j\xfa4F\x19\xfdN\x1f\x03\xa2\x1a\x06j\xc3(F\n\xceD\x1b\x12\xaf 4j\xf8\x16L3\xcaG"-\xa3\x1d;j\xf96F,\xedE\x1a\x04\xa0\x117`\xfa-G7\xcbD\r\x13\xa3\x07\'g\xc1\x0bK\x00\xf4I5\x0b\xa9\x1d/j\xfa4F\x19\xfdD\x07>\xa2\x18*`\xfa-G4\xe3D\x02\x11\xa3\x1e\x03g\xf6.G6\xcdI\x14 \xa2\x18<`\xfa-F\n\xceD\x1b\x12\xa3)8k\xfe;E\x13\xecD.\x05\xae!/k\xfe\x0cJ\x0e\xd5D\x17&\xa0\x0f!`\xfa-G4\xccD\x07&\xa2\x19(k\xfe(F\x07\xc0N\x1f\x03\xa1:)j\xf1?D\x19\xf4D\x1f\x05\xa9\x1d/i\xeb\x05K \xdcD.>\xa0!\x06j\xeb9G5\xe7E\x1a\x04\xa1\x06(k\xff>@\x0f\xc4F\'9\xa2\x1f.j\xcb\nG6\xcdI$,\xa2\x19.i\xc1)G5\xc8D%\n\xa9\x1d/j\xf9\x01F0\xd1E\x1a\x04\xa3\x02\x08j\xf99K5\xedE\x19\x01\xa3\x055g\xc6$L3\xcaF8\x19\xae\x1e\x1ej\xc3)F7\xdbF\'9\xa2\x1f.j\xfa4F\x19\xfdD\x07>\xa3,\x08k\xff*K\x08\xe5E\x1b\x02\xa0&+k\xfc/F\t\xc3N\x1f\x03\xa3\x1e\x03j\xf96G6\xcdD\x00$\xa3\x1e;g\xfc\nG5\xc8D\x07\x19\xae!&`\xfa-D\x14\xd0I\x1c2\xa3$+j\xfe<G6\xcdG\r\x05\xaf $`\xfa-E#\xf4G)*\xa2\x18(k\xfc/J\x16\xddE\x1b\x04\xa2\x18<l\xc6#K \xdcD\r\x13\xa3\x1d#j\xfa\x01F\x13\xe5D3#\xa9\x1d/k\xfd\x04F\n\xcfD&\x07\xa3\x19>f\xc76F1\xf1N\x1f\x03\xa0 \x01j\xfa9F0\xd1D\x00$\xa2\x18(i\xf65L3\xcaE\x1b\x02\xa3\x0f?j\xe0%K\x08\xecI,=\xae7\'`\xfa-F3\xd3D54\xa3\x05\x12k\xff(L3\xcaE\x18*\xa3\x00=j\xf9\x01K?\xc9E\x1a\x04\xae\x16\x0ck\xff>L3\xcaN\x1f\x03\xa2\x19.j\xe8=F)\xc2I$%\xae.\x11g\xd0%L3\xcaD\x1f\x1a\xa37\x18k\xff*E!\xccH"\x08\xa9\x1d/i\xea\x13E\x05\xe3E\x1a\x04\xa2\x1b-f\xdf:G7\xcdE\x1a\x10\xa5!!g\xe9;F!\xdaD\x1f\x0f\xa3\x1d\x03j\xda\x02F\x1f\xeaN\x1f\x03\xa2\x1a\x06j\xc3(F\n\xceD\x1b\x12\xaf 4j\xf8\x16L3\xcaG"-\xa3\x1d;j\xf96F,\xedE\x1a\x04\xa0\x117`\xfa-G7\xcbD\r\x13\xa3\x07\'g\xc1\x0bK\x00\xf4I5\x0b\xa9\x1d/j\xfa4F\x19\xfdD\x07>\xa2\x18*`\xfa-G4\xe3D\x02\x11\xa3\x1e\x03g\xf6.G6\xcdI\x14 \xa2\x18<`\xfa-F\n\xceD\x1b\x12\xa3)8k\xfe;E\x13\xecD.\x05\xae!/k\xfe\x0cJ\x0e\xd5D\x17&\xa0\x0f!`\xfa-G4\xccD\x07&\xa2\x19(k\xfe(F\x07\xc0N\x1f\x03\xa1:)j\xf1?D\x19\xf4D\x1f\x05\xa9\x1d/i\xeb\x05K \xdcD.>\xa0!\x06j\xeb9G5\xe7E\x1a\x04\xa1\x06(k\xff>@\x0f\xc4F\'9\xa2\x1f.j\xfa4F\x19\xfdD\x07>\xa3,\x08k\xff*K\x08\xe5E\x1b\x02\xa0&+k\xfc/F\t\xc3N\x1f\x03\xa3\x1e\x03j\xf96G6\xcdD\x00$\xa3\x1e;g\xfc\nG5\xc8D\x07\x19\xae!&`\xfa-D\x14\xd0I\x1c2\xa3$+j\xfe<G6\xcdG\r\x05\xaf $`\xfa-E#\xf4G)*\xa2\x18(k\xfc/J\x16\xddE\x1b\x04\xa2\x18<l\xc6#K \xdcD\r\x13\xa3\x1d#j\xfa\x01F\x13\xe5D3#\xa9\x1d/k\xfd\x04F\n\xcfD&\x07\xa3\x19>f\xc76F1\xf1N\x1f\x03\xa0 \x01j\xfa9F0\xd1D\x00$\xa2\x18(i\xf65L3\xcaE\x1b\x02\xa3\x0f?j\xe0%K\x08\xecI,=\xae7\'`\xfa-F3\xd3D54\xa3\x05\x12k\xff(L3\xcaE\x18*\xa3\x00=j\xf9\x01K?\xc9E\x1a\x04\xae\x16\x0ck\xff>L3\xcaN\x1f\x03\xa2\x19.j\xe8=F)\xc2I$%\xae.\x11g\xd0%L3\xcaD\x1f\x1a\xa37\x18j\xe2\x10G6\xcfN\x1f\x03\xa2\x1a\x06j\xe7?F0\xe6I\x13\x00\xa2\x18(g\xf1\x0eG6\xd9N\x1f\x03\xa3$+j\xfe<F\x07\xddE\x1b\x15\xa0=\tj\xcb+K\x0f\xcaE\x1b"\xaf 0j\xf2\x08E!\xc4N\x1f\x03\xa2\x1a)j\xe2\x08G7\xcdE\x1b\x06\xa3)%`\xfa-D\x14\xccD\x14\x11\xa17\x11j\xfa+L3\xcaG\x0e+\xae\x0e9j\xcb\x10E\x0f\xe3D\x0e\x17\xa2\x1b\x02k\xff*D(\xcdE\x1a\x10\xa5!!h\xc2\x17G1\xcbD.$\xa2\x18(g\xc1\x02G7\xcbG$\x07\xa2\x1b-j\xc0$L3\xcaD\x1c/\xa3\x1e4k\xff*F,\xedD\x1c\x17\xae\x1b\x08k\xfc/F+\xd0I#\n\xa9\x1d/h\xdd7K0\xfbD&\x07\xa3\x19>k\xff*E!\xccH"\x08\xa9\x1d/i\xea\x13E\x05\xe3E\x1a\x04\xa2\x1b-f\xdf:G7\xcdE\x1a\x10\xa5!!g\xe9;F!\xdaD\x1f\x0f\xa3\x1d\x03j\xda\x02F\x1f\xeaN\x1f\x03\xa2\x1a\x06j\xc3(F\n\xceD\x1b\x12\xaf 4j\xf8\x16L3\xcaG"-\xa3\x1d;j\xf96F,\xedE\x1a\x04\xa0\x117`\xfa-G7\xcbD\r\x13\xa3\x07\'g\xc1\x0bK\x00\xf4I5\x0b\xa9\x1d/j\xfa4F\x19\xfdD\x07>\xa2\x18*`\xfa-G4\xe3D\x02\x11\xa3\x1e\x03g\xf6.G6\xcdI\x14 \xa2\x18<`\xfa-F\n\xceD\x1b\x12\xa3)8k\xfe;E\x13\xecD.\x05\xae!/k\xfe\x0cJ\x0e\xd5D\x17&\xa0\x0f!`\xfa-G4\xccD\x07&\xa2\x19(k\xfe(F\x07\xc0N\x1f\x03\xa1:)j\xf1?D\x19\xf4D\x1f\x05\xa9\x1d/i\xeb\x05K \xdcD.>\xa0!\x06j\xeb9G5\xe7E\x1a\x04\xa1\x06(k\xff>@\x0f\xc4F\'9\xa2\x1f.j\xcb\nG6\xcdI$,\xa2\x19.i\xc1)G5\xc8D%\n\xa9\x1d/j\xf9\x01F0\xd1E\x1a\x04\xa3\x02\x08j\xf99K5\xedE\x1a\x06\xa9\x1d/k\xfd\x04F\n\xcfD&\x07\xa3\x19>f\xc76F1\xf1N\x1f\x03\xa0 \x01j\xfa9F0\xd1D\x00$\xa2\x18(i\xf65L3\xcaE\x1b\x02\xa3\x0f?j\xe0%K\x08\xecI,=\xae7\'`\xfa-F3\xd3D54\xa3\x05\x12k\xff(L3\xcaE\x18*\xa3\x00=j\xf9\x01K?\xc9E\x1a\x04\xae\x16\x0ck\xff>L3\xcaD&\x07\xa3\x19>j\xce:G7\xdcG?%\xa3,)g\xc6-G7\xebH"\x1c\xa3\x15\ni\xe8#L3\xcaE\x18\x05\xa3\x05\nk\xfe*G7\xcfD+\t\xa9\x1d/h\xdd+F8\xd8F5=\xa3\x1d)`\xfa-E"\xe2I\x0c\x15\xa3,\x12i\xc6\x04F"\xdeE\x19.\xa2\x18(h\xe1*G6\xd9B#\r\xa1%\x15k\xf8,F\x02\xedE\x1a\x04\xae&\x00k\xfe,E\x08\xceE\x19\x01\xa3\'&`\xfa-F0\xe6D\x1c\x18\xa2\x18(j\xe5\nF0\xdeI\x19$\xa2\x1b-j\xe27K\x0f\xc3N\x1f\x03\xa1:5g\xf9\x1cF\n\xceD\x1b\x12\xa2\x18(i\xe8+J\x0e\xc1N\x1f\x03\xa0\r\x11i\xcc\x04G6\xcdE\x19\x01\xaf88k\xfe*G6\xd9B#\r\xae\x0e9j\xe8=F3\xc6D\x1f/\xa3=\x00j\xd6\rL3\xcaE\x18*\xa3$*j\xc3)F7\xdbH"\x18\xa3\x1f\x14`\xfa-E\x0e\xe4D\x1f\x17\xa3\x1e4j\xe5\nG6\xcdG\x13\x1b\xa9\x1d/k\xfe,F!\xdaD\x05\x0b\xae&\tg\xc9\x13K\x19\xc2N\x1f\x03\xa3\x1d6j\xd0\x1aF+\xf7E\x1a\x06\xa9\x1d/k\xfd\x04F.\xd8D\x1c/\xae\x11,k\xff*K8\xe9E\x1a\x10\xa9\x1d/j\xc3)F7\xdbD+\x14\xa2\x199i\xda\x0bF\x02\xccI#\x03\xa2\x19\x0ef\xc72F;\xefG\r\r\xa9\x1d/k\xfd+F+\xefE\x1b\x04\xa2\x19*j\xce\'L3\xcaF8\x05\xa3\x16=h\xd0\x13F3\xccN\x1f\x03\xa0\x0c\x07g\xe9;F\x02\xf7G#*\xa3\x0c;k\xfc\x00G6\xcdF\x04\x04\xa2\x18<l\xc6#F.\xd8D\x1c/\xae\x11,'

print(ssss[2:4])  # == 140
# 与127做 与 位运算 12

# Websocket 加密 解密 3种情况
# 校验位 : 由websocket加密字符串的第二个字节与127期开始进行与位运算
# 校验位 == 127
# 校验位 == 126
# 校验位 <= 125

# 将第二个字节也就是 \x83 第9-16位 进行与127进行位运算
payload = hashstr[1] & 127
print(payload)
if payload == 127:
    extend_payload_len = hashstr[2:10]  # 15.5ZB
    mask = hashstr[10:14]
    decoded = hashstr[14:]
# 当位运算结果等于127时,则第3-10个字节为数据长度
# 第11-14字节为mask 解密所需字符串
# 则数据为第15字节至结尾

# ssss = b'\x81\xfe\x0bp\x8fF\xa1\xa3j\xc3)F7\xdbD+\x14\xa2\x199i\xda\x0bF\x02\xccI#\x03\xa2\x19\x0ef\xc72F;\xefG\r\r\xa9\x1d/k\xfd+F+\xefE\x1b\x04\xa2\x19*j\xce\'L3\xcaF8\x05\xa3\x16=h\xd0\x13F3\xccN\x1f\x03\xa0\x0c\x07g\xe9;F\x02\xf7G#*\xa3\x0c;k\xfc\x00G6\xcdF\x04\x04\xa2\x18<l\xc6#D\x0b\xf0E\x1d\x02\xa3,\x08k\xff*K\x08\xe5E\x1b\x02\xa0&+k\xfc/F\t\xc3N\x1f\x03\xa3\x1e\x03j\xf96G6\xcdD\x00$\xa3\x1e;g\xfc\nG5\xc8D\x07\x19\xae!&`\xfa-D\x14\xd0I\x1c2\xa3$+j\xfe<G6\xcdG\r\x05\xaf $`\xfa-E#\xf4G)*\xa2\x18(k\xfc/J\x16\xddE\x1b\x04\xa2\x18<l\xc6#K \xdcD\r\x13\xa3\x1d#j\xfa\x01F\x13\xe5D3#\xa9\x1d/k\xfd\x04F\n\xcfD&\x07\xa3\x19>f\xc76F1\xf1N\x1f\x03\xa0 \x01j\xfa9F0\xd1D\x00$\xa2\x18(i\xf65L3\xcaE\x1b\x02\xa3\x0f?j\xe0%K\x08\xecI,=\xae7\'`\xfa-G6\xcdI\x14 \xa2\x18<`\xfa-F\n\xceD\x1b\x12\xa3)8k\xfe;E\x13\xecD.\x05\xae!/k\xfe\x0cJ\x0e\xd5D\x17&\xa0\x0f!`\xfa-G4\xccD\x07&\xa2\x19(k\xfe(F\x07\xc0N\x1f\x03\xa1:)j\xf1?D\x19\xf4D\x1f\x05\xa9\x1d/i\xeb\x05K \xdcD.>\xa0!\x06j\xeb9G5\xe7E\x1a\x04\xa1\x06(k\xff>@\x0f\xc4F\'9\xa2\x1f.j\xcb\nG6\xcdI$,\xa2\x19.i\xc1)G5\xc8D%\n\xa9\x1d/j\xf9\x01F0\xd1E\x1a\x04\xa3\x02\x08j\xf99K5\xedE\x19\x01\xa3\x055g\xc6$L3\xcaF8\x19\xae\x1e\x1ej\xc3)F7\xdbE\x1a\x04\xa0\x0f)f\xc7&L3\xcaG\x0f=\xa0+\x06k\xff*G5\xc8H:\x14\xa2\x19(k\xff>@\x0f\xc4I\x0c\x15\xa3\x0f?j\xfa!F3\xe6D?,\xa31\x0fh\xc2\x17G1\xcbD\x1f\x1a\xa37\x18j\xe2\x10F\x02\xedE\x1a\x04\xae&\x00k\xfe,E\x08\xceE\x19\x01\xa3\'&`\xfa-F0\xe6D\x1c\x18\xa2\x18(j\xe5\nF0\xdeI\x19$\xa2\x1b-j\xe27K\x0f\xc3N\x1f\x03\xa1:5g\xf9\x1cF\n\xceD\x1b\x12\xa2\x18(i\xe8+J\x0e\xc1N\x1f\x03\xa0\r\x11i\xcc\x04G6\xcdE\x19\x01\xaf88k\xfe*G6\xd9B#\r\xae\x0e9j\xe8=F3\xc6D\x1f/\xa3=\x00j\xd6\rL3\xcaE\x18*\xa3$*j\xc3)F7\xdbH"\x18\xa3\x1f\x14`\xfa-E\x0e\xe4D\x1f\x17\xa3\x1e4j\xe5\nG6\xcdG\x13\x1b\xa9\x1d/k\xfe,F!\xdaD\x05\x0b\xae&\tg\xc9\x13K\x19\xc2N\x1f\x03\xa3\x1d6j\xd0\x1aF+\xf7E\x1a\x06\xa9\x1d/k\xfd\x04F.\xd8D\x1c/\xae\x11,k\xff*K8\xe9E\x1a\x10\xa9\x1d/`\xfa-G7\xcbD\r\x13\xa3\x07\'g\xc1\x0bK\x00\xf4I5\x0b\xa9\x1d/j\xfa4F\x19\xfdN\x1f\x03\xa2\x1a\x06j\xc3(F\n\xceD\x1b\x12\xaf 4j\xf8\x16L3\xcaG"-\xa3\x1d;j\xf96F,\xedE\x1a\x04\xa0\x117`\xfa-G7\xcbD\r\x13\xa3\x07\'g\xc1\x0bK\x00\xf4I5\x0b\xa9\x1d/j\xfa4F\x19\xfdD\x07>\xa2\x18*`\xfa-G4\xe3D\x02\x11\xa3\x1e\x03g\xf6.G6\xcdI\x14 \xa2\x18<`\xfa-F\n\xceD\x1b\x12\xa3)8k\xfe;E\x13\xecD.\x05\xae!/k\xfe\x0cJ\x0e\xd5D\x17&\xa0\x0f!`\xfa-G4\xccD\x07&\xa2\x19(k\xfe(F\x07\xc0N\x1f\x03\xa1:)j\xf1?D\x19\xf4D\x1f\x05\xa9\x1d/i\xeb\x05K \xdcD.>\xa0!\x06j\xeb9G5\xe7E\x1a\x04\xa1\x06(k\xff>@\x0f\xc4F\'9\xa2\x1f.j\xcb\nG6\xcdI$,\xa2\x19.i\xc1)G5\xc8D%\n\xa9\x1d/j\xf9\x01F0\xd1E\x1a\x04\xa3\x02\x08j\xf99K5\xedE\x19\x01\xa3\x055g\xc6$L3\xcaF8\x19\xae\x1e\x1ej\xc3)F7\xdbF\'9\xa2\x1f.j\xfa4F\x19\xfdD\x07>\xa3,\x08k\xff*K\x08\xe5E\x1b\x02\xa0&+k\xfc/F\t\xc3N\x1f\x03\xa3\x1e\x03j\xf96G6\xcdD\x00$\xa3\x1e;g\xfc\nG5\xc8D\x07\x19\xae!&`\xfa-D\x14\xd0I\x1c2\xa3$+j\xfe<G6\xcdG\r\x05\xaf $`\xfa-E#\xf4G)*\xa2\x18(k\xfc/J\x16\xddE\x1b\x04\xa2\x18<l\xc6#K \xdcD\r\x13\xa3\x1d#j\xfa\x01F\x13\xe5D3#\xa9\x1d/k\xfd\x04F\n\xcfD&\x07\xa3\x19>f\xc76F1\xf1N\x1f\x03\xa0 \x01j\xfa9F0\xd1D\x00$\xa2\x18(i\xf65L3\xcaE\x1b\x02\xa3\x0f?j\xe0%K\x08\xecI,=\xae7\'`\xfa-F3\xd3D54\xa3\x05\x12k\xff(L3\xcaE\x18*\xa3\x00=j\xf9\x01K?\xc9E\x1a\x04\xae\x16\x0ck\xff>L3\xcaN\x1f\x03\xa2\x19.j\xe8=F)\xc2I$%\xae.\x11g\xd0%L3\xcaD\x1f\x1a\xa37\x18k\xff*E!\xccH"\x08\xa9\x1d/i\xea\x13E\x05\xe3E\x1a\x04\xa2\x1b-f\xdf:G7\xcdE\x1a\x10\xa5!!g\xe9;F!\xdaD\x1f\x0f\xa3\x1d\x03j\xda\x02F\x1f\xeaN\x1f\x03\xa2\x1a\x06j\xc3(F\n\xceD\x1b\x12\xaf 4j\xf8\x16L3\xcaG"-\xa3\x1d;j\xf96F,\xedE\x1a\x04\xa0\x117`\xfa-G7\xcbD\r\x13\xa3\x07\'g\xc1\x0bK\x00\xf4I5\x0b\xa9\x1d/j\xfa4F\x19\xfdD\x07>\xa2\x18*`\xfa-G4\xe3D\x02\x11\xa3\x1e\x03g\xf6.G6\xcdI\x14 \xa2\x18<`\xfa-F\n\xceD\x1b\x12\xa3)8k\xfe;E\x13\xecD.\x05\xae!/k\xfe\x0cJ\x0e\xd5D\x17&\xa0\x0f!`\xfa-G4\xccD\x07&\xa2\x19(k\xfe(F\x07\xc0N\x1f\x03\xa1:)j\xf1?D\x19\xf4D\x1f\x05\xa9\x1d/i\xeb\x05K \xdcD.>\xa0!\x06j\xeb9G5\xe7E\x1a\x04\xa1\x06(k\xff>@\x0f\xc4F\'9\xa2\x1f.j\xfa4F\x19\xfdD\x07>\xa3,\x08k\xff*K\x08\xe5E\x1b\x02\xa0&+k\xfc/F\t\xc3N\x1f\x03\xa3\x1e\x03j\xf96G6\xcdD\x00$\xa3\x1e;g\xfc\nG5\xc8D\x07\x19\xae!&`\xfa-D\x14\xd0I\x1c2\xa3$+j\xfe<G6\xcdG\r\x05\xaf $`\xfa-E#\xf4G)*\xa2\x18(k\xfc/J\x16\xddE\x1b\x04\xa2\x18<l\xc6#K \xdcD\r\x13\xa3\x1d#j\xfa\x01F\x13\xe5D3#\xa9\x1d/k\xfd\x04F\n\xcfD&\x07\xa3\x19>f\xc76F1\xf1N\x1f\x03\xa0 \x01j\xfa9F0\xd1D\x00$\xa2\x18(i\xf65L3\xcaE\x1b\x02\xa3\x0f?j\xe0%K\x08\xecI,=\xae7\'`\xfa-F3\xd3D54\xa3\x05\x12k\xff(L3\xcaE\x18*\xa3\x00=j\xf9\x01K?\xc9E\x1a\x04\xae\x16\x0ck\xff>L3\xcaN\x1f\x03\xa2\x19.j\xe8=F)\xc2I$%\xae.\x11g\xd0%L3\xcaD\x1f\x1a\xa37\x18j\xe2\x10G6\xcfN\x1f\x03\xa2\x1a\x06j\xe7?F0\xe6I\x13\x00\xa2\x18(g\xf1\x0eG6\xd9N\x1f\x03\xa3$+j\xfe<F\x07\xddE\x1b\x15\xa0=\tj\xcb+K\x0f\xcaE\x1b"\xaf 0j\xf2\x08E!\xc4N\x1f\x03\xa2\x1a)j\xe2\x08G7\xcdE\x1b\x06\xa3)%`\xfa-D\x14\xccD\x14\x11\xa17\x11j\xfa+L3\xcaG\x0e+\xae\x0e9j\xcb\x10E\x0f\xe3D\x0e\x17\xa2\x1b\x02k\xff*D(\xcdE\x1a\x10\xa5!!h\xc2\x17G1\xcbD.$\xa2\x18(g\xc1\x02G7\xcbG$\x07\xa2\x1b-j\xc0$L3\xcaD\x1c/\xa3\x1e4k\xff*F,\xedD\x1c\x17\xae\x1b\x08k\xfc/F+\xd0I#\n\xa9\x1d/h\xdd7K0\xfbD&\x07\xa3\x19>k\xff*E!\xccH"\x08\xa9\x1d/i\xea\x13E\x05\xe3E\x1a\x04\xa2\x1b-f\xdf:G7\xcdE\x1a\x10\xa5!!g\xe9;F!\xdaD\x1f\x0f\xa3\x1d\x03j\xda\x02F\x1f\xeaN\x1f\x03\xa2\x1a\x06j\xc3(F\n\xceD\x1b\x12\xaf 4j\xf8\x16L3\xcaG"-\xa3\x1d;j\xf96F,\xedE\x1a\x04\xa0\x117`\xfa-G7\xcbD\r\x13\xa3\x07\'g\xc1\x0bK\x00\xf4I5\x0b\xa9\x1d/j\xfa4F\x19\xfdD\x07>\xa2\x18*`\xfa-G4\xe3D\x02\x11\xa3\x1e\x03g\xf6.G6\xcdI\x14 \xa2\x18<`\xfa-F\n\xceD\x1b\x12\xa3)8k\xfe;E\x13\xecD.\x05\xae!/k\xfe\x0cJ\x0e\xd5D\x17&\xa0\x0f!`\xfa-G4\xccD\x07&\xa2\x19(k\xfe(F\x07\xc0N\x1f\x03\xa1:)j\xf1?D\x19\xf4D\x1f\x05\xa9\x1d/i\xeb\x05K \xdcD.>\xa0!\x06j\xeb9G5\xe7E\x1a\x04\xa1\x06(k\xff>@\x0f\xc4F\'9\xa2\x1f.j\xcb\nG6\xcdI$,\xa2\x19.i\xc1)G5\xc8D%\n\xa9\x1d/j\xf9\x01F0\xd1E\x1a\x04\xa3\x02\x08j\xf99K5\xedE\x1a\x06\xa9\x1d/k\xfd\x04F\n\xcfD&\x07\xa3\x19>f\xc76F1\xf1N\x1f\x03\xa0 \x01j\xfa9F0\xd1D\x00$\xa2\x18(i\xf65L3\xcaE\x1b\x02\xa3\x0f?j\xe0%K\x08\xecI,=\xae7\'`\xfa-F3\xd3D54\xa3\x05\x12k\xff(L3\xcaE\x18*\xa3\x00=j\xf9\x01K?\xc9E\x1a\x04\xae\x16\x0ck\xff>L3\xcaD&\x07\xa3\x19>j\xce:G7\xdcG?%\xa3,)g\xc6-G7\xebH"\x1c\xa3\x15\ni\xe8#L3\xcaE\x18\x05\xa3\x05\nk\xfe*G7\xcfD+\t\xa9\x1d/h\xdd+F8\xd8F5=\xa3\x1d)`\xfa-E"\xe2I\x0c\x15\xa3,\x12i\xc6\x04F"\xdeE\x19.\xa2\x18(h\xe1*G6\xd9B#\r\xa1%\x15k\xf8,F\x02\xedE\x1a\x04\xae&\x00k\xfe,E\x08\xceE\x19\x01\xa3\'&`\xfa-F0\xe6D\x1c\x18\xa2\x18(j\xe5\nF0\xdeI\x19$\xa2\x1b-j\xe27K\x0f\xc3N\x1f\x03\xa1:5g\xf9\x1cF\n\xceD\x1b\x12\xa2\x18(i\xe8+J\x0e\xc1N\x1f\x03\xa0\r\x11i\xcc\x04G6\xcdE\x19\x01\xaf88k\xfe*G6\xd9B#\r\xae\x0e9j\xe8=F3\xc6D\x1f/\xa3=\x00j\xd6\rL3\xcaE\x18*\xa3$*j\xc3)F7\xdbH"\x18\xa3\x1f\x14`\xfa-E\x0e\xe4D\x1f\x17\xa3\x1e4j\xe5\nG6\xcdG\x13\x1b\xa9\x1d/k\xfe,F!\xdaD\x05\x0b\xae&\tg\xc9\x13K\x19\xc2N\x1f\x03\xa3\x1d6j\xd0\x1aF+\xf7E\x1a\x06\xa9\x1d/k\xfd\x04F.\xd8D\x1c/\xae\x11,k\xff*K8\xe9E\x1a\x10\xa9\x1d/j\xc3)F7\xdbD+\x14\xa2\x199i\xda\x0bF\x02\xccI#\x03\xa2\x19\x0ef\xc72F;\xefG\r\r\xa9\x1d/k\xfd+F+\xefE\x1b\x04\xa2\x19*j\xce\'L3\xcaF8\x05\xa3\x16=h\xd0\x13F3\xccN\x1f\x03\xa0\x0c\x07g\xe9;F\x02\xf7G#*\xa3\x0c;k\xfc\x00G6\xcdF\x04\x04\xa2\x18<l\xc6#F.\xd8D\x1c/\xae\x11,'
if payload == 126:
    extend_payload_len = hashstr[2:4]  # \x0bp\x8fF  65535 字节 21845个汉字
    mask = hashstr[4:8]  # xa1\xa3j\xc3)F7
    decoded = hashstr[8:]  # 从第九个开始全是数据
# 当位运算结果等于126时,则第3-4个字节为数据长度
# 第5-8字节为mask 解密所需字符串
# 则数据为第9字节至结尾

# hashstr = b'\x81\x8c\xc2J\xb3\x0c\xaa/\xdf`\xadj\xc4c\xb0&\xd7-'  12
if payload <= 125:
    extend_payload_len = None
    mask = hashstr[2:6]  # \xc2J\xb3\x0c\xaa
    decoded = hashstr[6:]  # /\xdf`\xadj\xc4c\xb0&\xd7-

# 当位运算结果小于等于125时,则这个数字12就是数据的长度
# 第3-6字节为mask 解密所需字符串
# 则数据为第7字节至结尾

str_byte = bytearray()
# mask_len = 4
# [0,1,2,3]
for i in range(len(decoded)): # 12 - 0 1 2 3 4 5 6 7 8 9 10 11
    byte = decoded[i] ^ mask[i % 4] # i=0
    str_byte.append(byte)

print(str_byte.decode("utf8"))

 3.加密原理 (简化)

import struct   # 把任何数字进行打包成4个字节

def res():
    msg_bytes = "hello".encode("utf8")
    token = b"\x81"      # 头部必加
    length = len(msg_bytes) # 5

    if length < 126:
        token += struct.pack("B", length)
    elif length == 126:
        token += struct.pack("!BH", 126, length)
    else:
        token += struct.pack("!BQ", 127, length)

    msg = token + msg_bytes

    print(msg)
    return msg

 源码解释:
https://www.cnblogs.com/wupeiqi/p/6558766.html

转载于:https://www.cnblogs.com/lw1095950124/p/10974189.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值