html5 http的轮询和Websocket原理

2019-01-28 11:26:01王冬梅

代码实现:

import socket, base64, hashlib # 创建socket连接 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定端地址和口号 sock.bind(('127.0.0.1', 9527)) # 监听 sock.listen(5) # 获取客户端socket对象 conn, address = sock.accept() # 获取客户端的【握手】信息 data = conn.recv(1024) print(data) def get_headers(data): """从请求头中取出Sec-WebSocket-Key对应的值并返回""" header_dict = {} header_str = data.decode("utf8") for i in header_str.split("rn"): if str(i).startswith("Sec-WebSocket-Key"): return i.split(":")[1].strip() # 得到Sec-WebSocket-Key对应的值 ws_key = get_headers(data) # 魔法字符串magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11 magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' # 拼接 socket_str = ws_key + magic_string # sha1加密 socket_str_sha1 = hashlib.sha1(socket_str.encode("utf8")).digest() # base64加密 socket_str_base64 = base64.b64encode(socket_str_sha1) # 拼接响应头 response_tpl = "HTTP/1.1 101 Switching Protocolsrn" "Upgrade:websocketrn" "Connection: Upgradern" "Sec-WebSocket-Accept: %srn" "WebSocket-Location: ws://127.0.0.1:9527rnrn" % (socket_str_base64.decode("utf8")) # 服务器发送响应头到客户端 conn.send(response_tpl.encode("utf8")) # 客户端服务端建立长连接循环接收发送数据 while True: msg = conn.recv(8096) print(msg)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> </body> <script type="text/javascript"> ws = new WebSocket("ws://127.0.0.1:9527"); ws.onmessage = function (ev) { console.log(ev)//用于接收数据 } </script> </html>

附带客户端发起HTTP请求的请求头:

b'GET /ws/ HTTP/1.1 Host: 127.0.0.1:9527 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.3... Upgrade: websocket Origin: http://localhost:63342 Sec-WebSocket-Version: 13 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Sec-WebSocket-Key: kJXuOKsrl3AR1KeFngRElQ== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits'

四、Websocket的加解密方式:

解密方式:

# b'x81x87x0exc3xf3xcd;xf6xc6xf8;xf6xc6'==========5555555 hashstr = b'x81x87x0exc3xf3xcd;xf6xc6xf8;xf6xc6' # 将第二个字节也就是 x87 第9-16位 进行与127进行位运算 payload = hashstr[1] & 127 # 当位运算结果等于127时,则第3-10个字节为数据长度 # 第11-14字节为mask 解密所需字符串 # 则数据为第15字节至结尾 if payload == 127: extend_payload_len = hashstr[2:10] mask = hashstr[10:14] decoded = hashstr[14:] # 当位运算结果等于126时,则第3-4个字节为数据长度 # 第5-8字节为mask 解密所需字符串 # 则数据为第9字节至结尾 if payload == 126: extend_payload_len = hashstr[2:4] mask = hashstr[4:8] decoded = hashstr[8:] # 当位运算结果小于等于125时,则这个数字就是数据的长度 # 第3-6字节为mask 解密所需字符串 # 则数据为第7字节至结尾 if payload <= 125: extend_payload_len = None mask = hashstr[2:6] decoded = hashstr[6:] str_byte = bytearray() for i in range(len(decoded)): byte = decoded[i] ^ mask[i % 4] str_byte.append(byte) print(str_byte.decode("utf8"))