• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Python实现websocket服务端

武飞扬头像
木 叶
帮助1

下面代码是使用python实现websocket后端服务;用于与前端网页进行通信

核心代码

from threading import Thread

import sys
import os
import base64
import hashlib
import socket
import struct


sys.path.append(os.path.abspath(os.path.dirname(__file__)   '/'   '..'))
sys.path.append("..")


class CaptureInfoWriteFile:
    def __init__(self,prot):
        # 应该new一个新的连接对象吧
        self.conns = []
        # 端口号进行加100, 避免运行多端时,端口重复,同时上限为100
        self.prots = prot 100
        # 创建一个websocket服务端
        sock = socket.socket()
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 绑定host,默认端口5000
        sock.bind(('127.0.0.1', self.prots))
        sock.listen(5)
        # 创建线程,等待客户端连接
        tt = Thread(target=self.connect_client, args=(sock,))
        tt.start()
        print("启动线程成功,开始监听服务端数据")
        print("-------------------------------------------------")
        # 开始获取前端传入的数据url ,X 和datas

    def get_headers(self,data):
        """
        将请求头转换为字典
        :param data: 解析请求头的data
        :return: 请求头字典
        """
        header_dict = {}
        data = str(data, encoding="utf-8")
        """
        请求头格式:
        b'
            GET / HTTP/1.1\r\n
            Host: 127.0.0.1:8080\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 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36\r\n
            Accept-Encoding: gzip, deflate, br\r\n
            Accept-Language: zh-CN,zh;q=0.8\r\n
            Sec-WebSocket-Key:  uL/aiakjNABjEoMzAqm6Q==\r\n
            Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n'
        """
        header, body = data.split("\r\n\r\n", 1)  # 因为请求头信息结尾都是\r\n,并且最后末尾部分是\r\n\r\n;
        # 所以以此分割
        header_list = header.split("\r\n")
        for i in range(0, len(header_list)):
            if i == 0:
                if len(header_list[0].split(" ")) == 3:
                    header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[0].split(" ")
            else:
                k, v = header_list[i].split(":", 1)
                header_dict[k] = v.strip()
        return header_dict

    def get_data(self,info):
        """
        对返回消息进行解码
        :param info: 原始消息
        :return: 解码之后的汉字
        """
        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')
        return body

    def send_data(self,conn,msg_bytes):
        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
        print(msg)
        conn.send(msg)
        return True

    def wait_data(self,conn):
        while True:
            data = conn.recv(8096)

            data = self.get_data(data)
            # 判断客户端是否已关闭
            if data=="关闭":
                print(f'客户端关闭了连接')
                break
            print("Receive msg==>", data)
            # send_data(conn, bytes("我是心的回复信息呀", encoding='utf-8'))
        conn.close()

    def connect_client(self,sock):
        conns = self.conns
        # 等待用户连接,一个线程只等待一个用户
        conn, addr = sock.accept()
        print("conn from==>", conn, addr)
        # 连接上后将其加入集合
        # 添加之前绑定上一个唯一的key,然后在取时,跟进key进行取
        # conns[str(prots)] = conn
        conns.append(conn)
        # 获取握手消息,magic string ,sha1加密
        # 发送给客户端
        # 握手消息
        data = conn.recv(8096)
        headers = self.get_headers(data)

        # 对请求头中的sec-websocket-key进行加密
        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"

        magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
        # 确认握手Sec-WebSocket-Key固定格式:headers头部的Sec-WebSocket-Key '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'])
        print(type(response_str))
        print(response_str)

        # 响应【握手】信息
        conn.send(bytes(response_str, encoding='utf-8'))
        #连接上后,处理客户端的收发信息
        th = Thread(target=self.wait_data, args=(conn,))
        th.start()



学新通

最后可以通过调取send_data方法,发送信息;get_data对发送过来的信息进行解析处理

注:如果代码有不理解的可以关注公众号: 测试开发分享 来提问

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgekkaj
系列文章
更多 icon
同类精品
更多 icon
继续加载