socket主动推送数据

此为服务端代码,前端可直接使用websocket测试工具即可

测试工具网址

http://www.websocket-test.com/
测试工具填写的websocket地址为: ws://127.0.0.1:8005

import socket
import base64
import hashlib
from queue import Queue
from threading import Thread
import struct
import copy
import json
import time

# from XX.redis_db import RedisDb

# from utils.summary import summary
# from utils.redis_util import RedisUtil
# import config

# redis_db = RedisDb(config.REDIS)
# redis_util = RedisUtil()

def insert_data():
    while True:
        q.put(input('请输入想要传输的数据:'))

class WebSocketUtil(object):
    global users
    users = set()

    def __init__(self, port=80, max_wait_user=5):
        self.sock = socket.socket()
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(("0.0.0.0", port))
        self.sock.listen(max_wait_user)
    def summary(self):
        """data为后端传输的数据"""
        data = q.get()
        # data = input('请输入数据')
        return data
    # 请求头转换格式为字典
    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[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 socket_connect(self):
        conn, addr = self.sock.accept()
        users.add(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'
        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'), )
        # 新的连接成功立马发一次数据
        data = "连接成功"
        self.send_msg(conn, bytes(json.dumps(data), encoding="utf-8"))

        # 添加redis,保存该连接最近推送消息的时间戳
        # redis_key = redis_util.get_md5_key(str(conn))
        # redis_db.str_set(redis_key, int(time.time()))

    def get_data(self, 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')
        return body

    # 向客户端发送数据
    def send_msg(self, conn, msg_bytes):
        """
        WebSocket服务端向客户端发送消息
        :param conn: 客户端连接到服务器端的socket对象,即: conn,address = socket.accept()
        :param msg_bytes: 向客户端发送的字节
        :return:
        """
        token = b"\x81"  # 接收的第一字节,一般都是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
        # 如果出错就是客户端断开连接
        try:
            conn.send(msg)
        except Exception as e:
            # 删除断开连接的记录
            users.remove(conn)

    # 循环等待客户端建立连接
    def wait_socket_connect(self):
        while True:
            self.socket_connect()

    # socket服务端监听客户端连接并批量推送数据
    def start_socket_server(self):
        # 启线程循环等待客户端建立连接
        Thread(target=self.wait_socket_connect).start()
        # 消息推送
        while True:
            # 判断是否有客户端连接,有才推送消息
            if len(users):
                send_users = copy.copy(users)
                # 自定义的消息内容
                data = self.summary()
                # 遍历
                for user in send_users:
                    # 判断该连接是否最近5s推送消息(可配置时间),有就跳过
                    # if self.get_connect_last_send_time(user):
                    self.send_msg(user, bytes(json.dumps(data), encoding="utf-8"))
                    # else:
                    #     pass
                # time.sleep(config.FLUSH_TIME)
                time.sleep(3)
    # # 获取该连接最近推送消息的时间戳并判断是否在阀值内
    # def get_connect_last_send_time(self, conn, time_threshold=config.TIME_THRESHOLD):
    #     try:
    #         redis_key = redis_util.get_md5_key(str(conn))
    #         last_send_time = int(redis_db.str_get(redis_key) or 0)
    #         return True if time.time() - last_send_time > time_threshold else False
    #     except Exception as e:
    #         return True


if __name__ == '__main__':
    q = Queue()
    Thread(target=insert_data).start()
    web = WebSocketUtil(port=8005)
    web.start_socket_server()

转载:https://blog.csdn.net/qq_30966497/article/details/103637557

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值