websocket握手原理及简单的网页聊天室

一.websocket响应握手信息即封包解包原理:

服务端

import socket
import base64
import hashlib

#封包
def send_msg(conn, msg_bytes):
    """
    WebSocket服务端向客户端发送消息
    :param conn: 客户端连接到服务器端的socket对象,即: conn,address = socket.accept()
    :param msg_bytes: 向客户端发送的字节
    :return:
    """
    import struct

    token = b"x81"
    length = len(msg_bytes)
    if length < 126:
        token += struct.pack("B", length)
    elif length <= 0xFFFF:
        token += struct.pack("!BH", 126, length)
    else:
        token += struct.pack("!BQ", 127, length)

    msg = token + msg_bytes
    conn.send(msg)
    return True

def get_headers(data):
    """
    将请求头格式化成字典
    :param data:
    :return:
    """
    header_dict = {}
    data = str(data, encoding='utf-8')

    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)

conn, address = sock.accept()
data = conn.recv(1024)
headers = get_headers(data)  # 提取请求头信息
# 对请求头中的sec-websocket-key进行加密
response_tpl = "HTTP/1.1 101 Switching Protocols
" 
               "Upgrade:websocket
" 
               "Connection: Upgrade
" 
               "Sec-WebSocket-Accept: %s
" 
               "WebSocket-Location: ws://%s%s

"
magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
value = headers['Sec-WebSocket-Key'] + magic_string
ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
response_str = response_tpl % (ac.decode('utf-8'), headers['Host'], headers['url'])
# 响应【握手】信息
conn.send(bytes(response_str, encoding='utf-8'))

# b'x81x87xbe0xb4xc7xc7Qxdaxabxd1^xd3'
# msg[1] & 127
#
# 10100011
# 01111111
# 00100011 <= 125 # x81x87    xbe0xb4xc7xc7Q xdaxabxd1^xd3'
# 00100011 == 126 # x81x87xbe0xb4    xc7xc7Qxdaxab xd1^xd3'xbe0xb4xc7xc7Qxdaxabxd1^xd3'
# 00100011 == 127 # x81x87 + 8个字节   内容
# mask
# for i in xc7Q xdaxabxd1^xd3':
#     xc7Q mask

#解包
while True:
    info = conn.recv(8096)
    print('收到数据',info)

    payload_len = info[1] & 127
    if payload_len == 126:
        extend_payload_len = info[2:4]
        mask = info[4:8]
        decoded = info[8:]
    elif payload_len == 127:
        extend_payload_len = info[2:10]
        mask = info[10:14]
        decoded = info[14:]
    else:
        extend_payload_len = None
        mask = info[2:6]
        decoded = info[6:]

    bytes_list = bytearray()
    for i in range(len(decoded)):
        chunk = decoded[i] ^ mask[i % 4]
        bytes_list.append(chunk)
    body = str(bytes_list, encoding='utf-8')
    print(body)

    send_msg(conn,b'nononononono')

conn.close()

  

客户端(浏览器):

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <div id="content">
 9 
10     </div>
11 
12     <script type="text/javascript">
13         var socket = new WebSocket("ws://127.0.0.1:8002");
14         socket.onmessage = function (event) {
15             /* 服务器端向客户端发送数据时,自动执行 */
16             var response = event.data;
17             var newTag = document.createElement('div');
18             newTag.innerHTML = response;
19             document.getElementById('content').appendChild(newTag);
20         };
21     </script>
22 </body>
23 </html>

客户端其它方法

<script type="text/javascript">
    var socket = new WebSocket("ws://127.0.0.1:8003/chatsocket");
 
    socket.onopen = function () {
        /* 与服务器端连接成功后,自动执行 */
 
        var newTag = document.createElement('div');
        newTag.innerHTML = "【连接成功】";
        document.getElementById('content').appendChild(newTag);
    };
 
    socket.onmessage = function (event) {
        /* 服务器端向客户端发送数据时,自动执行 */
        var response = event.data;
        var newTag = document.createElement('div');
        newTag.innerHTML = response;
        document.getElementById('content').appendChild(newTag);
    };
 
    socket.onclose = function (event) {
        /* 服务器端主动断开连接时,自动执行 */
        var newTag = document.createElement('div');
        newTag.innerHTML = "【关闭连接】";
        document.getElementById('content').appendChild(newTag);
    };
 
    function sendMsg() {
        var txt = document.getElementById('txt');
        socket.send(txt.value);
        txt.value = "";
    }
    function closeConn() {
        socket.close();
        var newTag = document.createElement('div');
        newTag.innerHTML = "【关闭连接】";
        document.getElementById('content').appendChild(newTag);
    }
 
</script>

  

web聊天室:

参考 这里

原文地址:https://www.cnblogs.com/mitsui/p/7545877.html