python - websocket

本文详细介绍了WebSocket与HTTP的区别,WebSocket是一种在客户端和服务器之间建立长连接的协议,支持双向通信,而HTTP则是典型的请求-响应模式。通过示例展示了WebSocket的握手过程,包括客户端和服务器的交互步骤。同时,提供了Python实现的WebSocket服务端和HTML客户端的源码,帮助理解WebSocket的工作机制。
摘要由CSDN通过智能技术生成

原学习地址:https://www.bilibili.com/video/BV1B4411L7PF?share_source=copy_web

概述

  • HTTP,socket实现,短链接,请求响应
  • Websocket,socket实现,双工通道,请求响应,推送。不断开

socket入手

  • 服务端(socket)服务器

1、服务器开启socket,监听IP和端口
3、允许连接
5、* 服务端接收到特殊值【特殊值加密sha1,migic string=‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’】,固定值
6、* 加密后的值发送给客户端

  • 客户端(浏览器)

2、客户端发起连接请求(IP和端口)
4、* 客户端生成一个XXX,【特殊值加密sha1,migic string=‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’】向服务端发送一段特殊值
7、* 客户端收到加密的值

  • websocket客户端发给服务端的帧
    在这里插入图片描述
    图片来自网图

客户端源码

<!--
 * @LastEditTime: 2021-05-17 16:44:31
 * @FilePath: \Python-project\OemWeb\firstWEB\templates\st_result.html
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试结果显示</title>
</head>
<body>
    <h1>
        测试结果显示页面
    </h1>
    <script>
        ws = new WebSocket("ws://127.0.0.1:8002");
        ws.onopen = function () {
            console.log(1111);
            ws.send('hello');
        }
        ws.onmessage = function (event) {
            console.log(event)
        }
        ws.onclose = function () {
        }
    </script>
</body>
</html>

服务端源码

class WebServerSocket:
    def __init__(self, server_ip, server_port):
        self.server_ip = server_ip
        self.server_port = server_port
        self.conn = None

        # 创建服务器
        self.sock = socket(AF_INET, SOCK_STREAM)
        self.sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        self.sock.bind((self.server_ip, self.server_port))
        self.sock.listen(5)

        # 一个永远都在接收新连接的线程
        t = threading.Thread(target=self.socket_server_wait_create, args=())
        t.start()

    # 一个永远都在接收新连接的线程对应的函数
    def socket_server_wait_create(self):
        while True:
            # 等待用户连接
            self.conn, address = self.sock.accept()
            # 握手消息
            data = self.conn.recv(8096)
            headers = self.get_headers(data)
            # for k, v in headers.items():
            #     print(k, v)
            # 获取[握手消息],magic string,sha1加密
            magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
            value = headers['Sec-WebSocket-Key'] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
            ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())

            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://%s%s\r\n\r\n"

            # 发送回客户端
            response_str = response_tpl % (ac.decode('utf-8'), headers['Host'], headers['url'])
            self.conn.send(bytes(response_str, encoding='utf-8'))
            self.send_msg("wbsocket connected!")
            print("wbsocket connected!", str(headers['Host']), str(headers['url']))

    # 把网页给的数据格式化为字典,这里是为了获取随机字符串,给魔术字符串加密建立连接
    def get_headers(self, data):
        """
        将请求头格式化成字典
        """
        header_dict = {}
        data = str(data, encoding="utf-8")

        header, body = data.split('\r\n\r\n', 1)
        header_list = header.split('\r\n')
        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()
        # print(header_dict)
        return header_dict

    # 接收数据  
    def get_msg(self):
        info = self.conn.recv(8096)
        payload_len = info[1] & 127
        if payload_len == 126:
            extend_payload_len = info[2:4]
            mask = info[4:8]
            decode = info[8:]
        elif payload_len == 127:
            extend_payload_len = info[2:10]
            mask = info[10:14]
            decode = info[14:]
        else:
            extend_payload_len = None
            mask = info[2:6]
            decode = info[6:]

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

    # 发送数据
    def send_msg(self, msg_bytes):
        token = b"\x81"
        msg_bytes = bytes(msg_bytes.encode('utf-8'))
        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
        self.conn.send(msg)
        return True

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值