你真的了解WebSocket吗?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你真的了解WebSocket吗?相关的知识,希望对你有一定的参考价值。
WebSocket协议是基于TCP的一种新的协议。WebSocket最初在html5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与服务器全双工(full-duplex)通信。其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信。
本文将使用Python编写Socket服务端,一步一步分析请求过程!!!
1. 启动服务端
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((‘127.0.0.1‘, 8002)) sock.listen(5) # 等待用户连接 conn, address = sock.accept() print(‘我来了‘,conn)
启动Socket服务器后,等待用户【连接】,然后进行收发数据。
2. 客户端连接
<body>
<script>
var ws = new WebSocket(‘ws://127.0.0.1:8002‘)
</script>
</body>
当客户端向服务端发送连接请求时,不仅连接还会发送【握手】信息,并等待服务端响应,至此连接才创建成功!
我来了 <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0,
laddr=(‘127.0.0.1‘, 8002), raddr=(‘127.0.0.1‘, 9089)>
3. 建立连接【握手】
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((‘127.0.0.1‘, 8002)) sock.listen(5) # 等待用户连接 conn, address = sock.accept() # print(‘我来了‘,conn)
# 接收信息 msg = conn.recv(8096) print(msg)
# msg的信息
GET / HTTP/1.1 Host: 127.0.0.1:8002 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 Upgrade: websocket Origin: http://localhost:63342 Sec-WebSocket-Version: 13 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: m_lvt_b3a3fc356d0af38b811a0ef8d50716b8=1552050219;
csrftoken=zMIqQhUHFPKDYrSfRKXlYziC48Hhr9gybHn5dhT1YCxjWWL0hpFpbhpEK2f1ZveI;
OUTFOX_SEARCH_USER_ID_NCOO=365670935.15332246;
session=eyJfcGVybWFuZW50Ijp0cnVlLCJ1c2VyX2lkIjoxfQ.EKbEWg.e-R5XugNGe1_STfG3K8B3jqDTkk Sec-WebSocket-Key: NQ+slWNHq4Xy8xlVMKCNtg== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
请求和响应的【握手】信息需要遵循规则:
- 从请求【握手】信息中提取 Sec-WebSocket-Key
- 利用magic_string 和 Sec-WebSocket-Key 进行hmac1加密,再进行base64加密
- 将加密结果响应给客户端
注:magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11 就是这个 不能修改
import socket import base64 import hashlib def get_headers(data): """ 将请求头格式化成字典 :param data: :return: """ header_dict = {} data = str(data, encoding=‘utf-8‘) # for i in data.split(‘ ‘): # print(i) header, body = data.split(‘ ‘, 1) header_list = header.split(‘ ‘) for i in range(0, len(header_list)): if i == 0: if len(header_list[i].split(‘ ‘)) == 3: header_dict[‘method‘], header_dict[‘url‘], header_dict[‘protocol‘] = header_list[i].split(‘ ‘) else: k, v = header_list[i].split(‘:‘, 1) header_dict[k] = v.strip() return header_dict sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((‘127.0.0.1‘, 8002)) sock.listen(5) # 1. 等待用户连接 conn, address = sock.accept() # 2. 接收验证消息 data = conn.recv(1024) headers = get_headers(data) # 提取请求头信息 magic_string = ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11‘ # 3. 对数据加密 value = headers[‘Sec-WebSocket-Key‘] + magic_string ac = base64.b64encode(hashlib.sha1(value.encode(‘utf-8‘)).digest()) # 4. 将加密之后的数据返回 # 对请求头中的sec-websocket-key进行加密 response_tpl = "HTTP/1.1 101 Switching Protocols " "Upgrade:websocket " "Connection: Upgrade " "Sec-WebSocket-Accept: %s " "WebSocket-Location: ws://%s%s " response_str = response_tpl % (ac.decode(‘utf-8‘), headers[‘Host‘], headers[‘url‘]) conn.send(bytes(response_str, encoding=‘utf-8‘)) # 5. 接收用户传过来的信息 while True: msg = conn.recv(8096) print(msg)
在浏览器中的console中 发送
ws.send(123445)
# 这个时候在前端就会收到 加密之后的msg
b"x81x86x0c‘W*=x15dx1e8x12"
我们得到的是一串加密的数据 我们怎么才可以读懂呢?
4.客户端和服务端收发数据
客户端和服务端传输数据时,需要对数据进行【封包】和【解包】。客户端的javascript类库已经封装【封包】和【解包】过程,但Socket服务端需要手动实现。
解包详细过程:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-------+-+-------------+-------------------------------+ |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len==126/127) | | |1|2|3| |K| | | +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + | Extended payload length continued, if payload len == 127 | + - - - - - - - - - - - - - - - +-------------------------------+ | |Masking-key, if MASK set to 1 | +-------------------------------+-------------------------------+ | Masking-key (continued) | Payload Data | +-------------------------------- - - - - - - - - - - - - - - - + : Payload Data continued ... : + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Payload Data continued ... | +---------------------------------------------------------------+
我们拿到加密后的数据 b"x81x86x0c‘W*=x15dx1e8x12" 我们可以看到上面的数字 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 就是我们切割拿到的加密数据的第二位 与 (01111111)127做 & (位)运算 得到的结果 分三种情况 如果是127: b"x81x86x0c‘W*=x15d x1e8x12" 如果是126: b"x81x86x0c‘W*= x15dx1e8x12" 如果是小于等于125: b"x81x86 x0c‘W*=x15dx1e8x12"
第一步:获取客户端发送的数据【解包】
以上是关于你真的了解WebSocket吗?的主要内容,如果未能解决你的问题,请参考以下文章