websocket --- 05 . http与websocket
一.http协议
1.基于 TCP 协议
2.一次请求 一次响应 断开
3.客户端永远处于主动状态
4.服务器永远处于被动状态
5.Http无状态 - 在服务器不保存客户端的信息
6.服务器无法主动找到客户端
二.轮询,长轮询,长连接
1.轮询
客户端向服务器不断发起类似Http请求 服务器不断的响应客户端
举例: 带上你的身份牌 - 服务器校验身份 大爷去找你的消息 - 服务器获取你应该拿到数据 if:拿到数据 else:拿不到数据 - 再次发起请求询问服务器消息 劣势: 1.双端资源浪费 2.带宽资源占用 3.不能保证数据实时性 上个世纪90年代 - 本世纪初: 24bps == 4-6KB CPU == 800MHZ 内存 == 256MB QQ -- ICQ
2.长轮询
1.客户端向服务器发起一个请求 2.服务器保持这个请求 不返回不响应 3.一定时间之后,服务器抛弃 or 返回 4.客户端收到请求 立即再次发起保持
举例: 你去传达室,大爷款待你喝茶, 喝茶等消息(保持) 上厕所(断开) 再次回去喝茶等消息(保持) 劣势: 1.服务器资源浪费 2.不能保证数据实时性 优势: 1.节省客户端资源 2.保证数据有效 当时的环境:本世纪初 - 目前 128bps == 20-30KB Cpu == 1.4GHZ 奔腾4 内存 == 512MB
3.长连接
永久保持连接
举例: 1.你和大爷之间装了一台电话分机 2.你派人告诉大爷你的分机号码 3.大爷拨通分机 4.你告诉大爷,有消息说句话,我派人去拿 5.你和大爷同时开启了闭音 劣势: 1.服务器CPU要求较高 优势: 1.节省大量资源 2.数据实时有效性 3.带宽几乎不占用 现在的环境: 100mps == 百兆光纤 == 5MB/s || 2KB CPU == 16核32线程 i9 3.2GHZ 内存 == 16GB
三.websocket
1.三方组件:gevent-Websocket
ws协议 ws://127.0.0.1 javascript封装客户端 http协议 http://127.0.0.1
三方:geventWebsocket Flask
Web框架 :用来进行Http请求的处理 (握手)
2. 群发实例(websocket+flask 框架)
①在.py 文件中
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_list = [] #存放所有建立好的连接 @app.route("/my_app") def my_app(): return render_template("my_app.html") @app.route("/my_ws") def my_ws():
# print(request.environ) user_socket = request.environ.get("wsgi.websocket") # type:WebSocket user_socket_list.append(user_socket) print(len(user_socket_list),user_socket_list) while 1: try: msg = user_socket.receive() # 阻塞等待消息数据 except WebSocketError: user_socket_list.remove(user_socket) #如果连接不存在,删除此连接 return "good bye" # http 请求必须要有 return for u in user_socket_list: if u == user_socket: continue try: u.send(msg) #如果失败给下一个发送 except : continue 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="message">
<button onclick="send_message()">发送</button> <div id="chat_list"> </div> </body> <script type="application/javascript"> var ws = new WebSocket("ws://127.0.0.1:9527/my_ws"); ws.onmessage = function (eventMessage) { # 回调函数,返回的存放数据
// console.log(enventMessage) // document.getElementById("chat_list").innerHTML += "<p>" + eventMessage.data + "</p>"; var p = document.createElement("p"); #创建p标签 p.innerText = eventMessage.data; #将数据添加到p标签 document.getElementById("chat_list").appendChild(p); #将p标签填入 }; function send_message() { var message = document.getElementById("message").value; ws.send(message); } </script> </html>
3.单聊
收发快递模型: 寄件人:user1 from_user 收件人:user2 to_user 包裹 user2: 寄件人是user1 打开包裹 - 被骂了 骂回去: 寄件人:user2 收件人:user1 包裹 user1: 寄件人是user2 打开包裹 - 骂回来了 对骂吧: 寄件人:user1 收件人:user2 包裹
① 在 .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