• websocket通信


    python后端与web前端的websocket通信

    目的:实现本地exe和浏览器插件的双向通信。
    服务端:本地exe(python)
    客户端:浏览器插件(js)
    参考文章:
    https://battlehawk233.cn/post/418.html
    http://www.noobyard.com/article/p-zjvfszlp-ea.html

    websocket原理

    百度百科
    单个TCP连接上的全双工通信协议。
    使得C/S间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
    在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

    客户端

    浏览器插件中添加websocket发送,接收代码。这里通过客户端主动关闭连接,以处理打开后的连接关闭问题。

    // 创建WebSocket连接.
    console.log('建立socket连接');
    const socket = new WebSocket('ws://localhost:8000');
     
    // 连接成功触发
    socket.addEventListener('open', function (event) {
        socket.send('Hello Server!');
    });
     
    // 监听消息
    socket.addEventListener('message', function (event) {
        console.log('Message from server ', event.data);
    });
    //监听失败
    socket.addEventListener('error', function (event){
        console.log('Error from server ', event);
    })
    //监听关闭
    socket.addEventListener('close', function(event) {
        console.log('Close from server ', event);
    })
    // 主动关闭socket
    socket.close();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    服务端

    使用这个代码
    服务端代码,允许多个客户端连接,并实现广播消息。

    # -*- coding: utf-8 -*-
    # @Time    : 2019/3/12 10:11
    # @Author  : 甄超锋
    # @Email   : 4535@sohu.com
    # @File    : severs.py
    # @Software: PyCharm
    import socket
    import base64
    import hashlib
    from threading import Thread
    import struct
    import copy
    
    global users
    users = set()
    
    
    def get_headers(data):
    	'''将请求头转换为字典'''
    	header_dict = {}
    
    	data = str(data, encoding="utf-8")
    
    	header, body = data.split("\r\n\r\n", 1)
    	header_list = header.split("\r\n")
    	print("---"*22, body)
    	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
    
    
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(("0.0.0.0", 8000))
    sock.listen(5)
    
    
    # 等待用户连接
    def acce():
    	conn, addr = sock.accept()
    	print("conn from ", conn, addr)
    	users.add(conn)
    	# 获取握手消息,magic string ,sha1加密
    	# 发送给客户端
    	# 握手消息
    
    	data = conn.recv(8096)
    	headers = 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'),)
    
    
    def get_data(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(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:
    		print(e)
    		# 删除断开连接的记录
    		users.remove(conn)
    
    # 循环等待客户端建立连接
    def th():
    	while True:
    		acce()
    
    
    if __name__ == '__main__':
    	# 循环建立连接创建一个线程
    	Thread(target=th).start()
    	# 循环群发
    	while True:
    		message = input("输入发送的数据")
    		s_2 = copy.copy(users)
    		for u in s_2:
    			print(u)
    			send_msg(u, bytes(message, encoding="utf-8"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
  • 相关阅读:
    PASCAL VOC2012 数据集讲解与制作自己的数据集
    阿里P8推崇不已的Java4大开源框架,大厂面试必问底层文档
    spring3.2框架用原始的方式启动后,接口一直404,应该怎么解决
    Android自定义View之可拖拽悬浮控件 代码赏析
    有一个工资高的工作,我却不敢去
    NetSuite Account Register报表详解
    Three.js——基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质
    分布式搜索引擎ElasticSearch-1
    Unity——利用Mesh绘制图形
    Apollo 应用与源码分析:CyberRT-时间相关API
  • 原文地址:https://blog.csdn.net/baidu_37336262/article/details/126709780