您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道

5b51 2022/1/14 8:25:00 python 字数 13188 阅读 904 来源 www.jb51.cc/python

2、websocket的优点 以前webserver实现推送技术或者即时通讯,用的都是轮询(polling),在特点的时间间隔(比如1秒钟)由浏览器自动发出请求,将服务器的消息主动的拉回来,在这种情况下,我们需要不断的向服务

概述

WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道

2、websocket的优点

以前web server实现推送技术或者即时通讯,用的都是轮询(polling),在特点的时间间隔(比如1秒钟)由浏览器自动发出请求,将服务器的消息主动的拉回来,在这种情况下,我们需要不断的向服务器发送请求,然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽和服务器资源。

进群:548377875   即可获取数十套PDF哦!

而最比较新的技术去做轮询的效果是Comet – 用了AJAX。但这种技术虽然可达到全双工通信,但依然需要发出请求(reuqest)。

WebSocket API最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。 浏览器和服务器只需要要做一个握手的动作,在建立连接之后,服务器可以主动传送数据给客户端,客户端也可以随时向服务器发送数据。 此外,服务器与客户端之间交换的标头信息很小。

WebSocket并不限于以Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;

因此从服务器角度来说,websocket有以下好处:

WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道

3.3基于sha加密方式的握手协议

也是目前见的最多的一种方式,这里的版本号目前是需要13以上的版本。

客户端请求:

WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道

3.4、基于sha加密的opening Handshake(握手环节)

客户端发起连接Handshake请求

WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道

Data Framing

Websocket协议通过序列化的数据帧传输数据。数据封包协议中定义了opcode、payload length、Payload data等字段。其中要求:

针对上情况,发现错误的一方可向对方发送close帧(状态码是1002,表示协议错误),以关闭连接。

WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道

WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道

Payload length

Payload data的长度,占7bits,7+16bits,7+64bits:

这里的长度表示遵循一个原则,用最少的字节表示长度(尽量减少不必要的传输)。举例说,payload真实长度是124,在0-125之间,必须用前7位表示;不允许长度1是126或127,然后长度2是124,这样违反原则。

Payload data

应用层数据

server解析client端的数据

接收到客户端数据后的解析规则如下:

1byte

1bit: frame-fin,x0表示该message后续还有frame;x1表示是message的最后一个frame

3bit: 分别是frame-rsv1、frame-rsv2和frame-rsv3,通常都是x0

4bit: frame-opcode,x0表示是延续frame;x1表示文本frame;x2表示二进制frame;x3-7保留给非控制frame;x8表示关 闭连接;x9表示ping;xA表示pong;xB-F保留给控制frame

2byte

1bit: Mask,1表示该frame包含掩码;0表示无掩码

7bit、7bit+2byte、7bit+8byte: 7bit取整数值,若在0-125之间,则是负载数据长度;若是126表示,后两个byte取无符号16位整数值,是负载长度;127表示后8个 byte,取64位无符号整数值,是负载长度

3-6byte: 这里假定负载长度在0-125之间,并且Mask为1,则这4个byte是掩码

7-end byte: 长度是上面取出的负载长度,包括扩展数据和应用数据两部分,通常没有扩展数据;若Mask为1,则此数据需要解码,解码规则为- 1-4byte掩码循环和数据byte做异或操作。

示例代码

while True:

# 对数据进行解密

# send_msg(conn,bytes('alex',encoding='utf-8'))

# send_msg(conn,bytes('SB',encoding='utf-8'))

# info = conn.recv(8096)

# print(info)

info = conn.recv(8096)

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)

msg = str(bytes_list,encoding='utf-8')

rep = msg + 'sb'

send_msg(conn,bytes(rep,encoding='utf-8'))

5、原理代码

后端

import socket

import hashlib

import base64

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

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

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()

# WebSocket发来的连接

# 1. 获取握手数据

data = conn.recv(1024)

headers = get_headers(data)

# 2. 对握手信息进行加密:

magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'

value = headers['Sec-WebSocket-Key'] + magic_string

ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())

# 3. 返回握手信息

response_tpl = "HTTP/1.1 101 Switching Protocols "

"Upgrade:websocket "

"Connection: Upgrade "

"Sec-WebSocket-Accept: %s "

"WebSocket-Location: ws://127.0.0.1:8002 "

response_str = response_tpl % (ac.decode('utf-8'),)

conn.sendall(bytes(response_str,encoding='utf-8'))

# 之后,才能进行首发数据。

while True:

# 对数据进行解密

# send_msg(conn,encoding='utf-8'))

二、应用:

1、Flask中应用: pip3 install gevent-websocket

View Code

from flask import Flask,request,render_template,session,redirect

import uuid

import json

from geventwebsocket.handler import WebSocketHandler

from gevent.pywsgi import WSGIServer

app = Flask(__name__)

app.secret_key = 'asdfasdf'

GENTIEMAN = {

'1':{'name':'钢弹','count':0},

'2':{'name':'铁锤',

'3':{'name':'闫帅',

}

WEBSOCKET_DICT = {

}

@app.before_request

def before_request():

if request.path == '/login':

return None

user_info = session.get('user_info')

if user_info:

return None

return redirect('/login')

@app.route('/login',methods=['GET','POST'])

def login():

if request.method == "GET":

return render_template('login.html')

else:

uid = str(uuid.uuid4())

session['user_info'] = {'id':uid,'name':request.form.get('user')}

return redirect('/index')

@app.route('/index')

def index():

return render_template('index.html',users=GENTIEMAN)

@app.route('/message')

def message():

# 1. 判断到底是否是websocket请求?

ws = request.environ.get('wsgi.websocket')

if not ws:

return "请使用WebSocket协议"

# ----- ws连接成功 -------

current_user_id = session['user_info']['id']

WEBSOCKET_DICT[current_user_id] = ws

while True:

# 2. 等待用户发送消息,并接受

message = ws.receive() # 帅哥ID

# 关闭:message=None

if not message:

del WEBSOCKET_DICT[current_user_id]

break

# 3. 获取用户要投票的帅哥ID,并+1

old = GENTIEMAN[message]['count']

new = old + 1

GENTIEMAN[message]['count'] = new

data = {'user_id': message,'count': new,'type':'Vote'}

# 4. 给所有客户端推送消息

for conn in WEBSOCKET_DICT.values():

conn.send(json.dumps(data))

return 'close'

@app.route('/notify')

def notify():

data = {'data': "你的订单已经生成,请及时处理;",'type': 'alert'}

print(WEBSOCKET_DICT)

for conn in WEBSOCKET_DICT.values():

conn.send(json.dumps(data))

return '发送成功'

if __name__ == '__main__':

http_server = WSGIServer(('192.168.11.143',5000),app,handler_class=WebSocketHandler)

http_server.serve_forever()

login.html

<Meta charset="UTF-8">

Title

login.html

index.html

<Meta charset="UTF-8">

Title

{% for k,v in users.items() %}

{% endfor %}

2、Django应用:channel

3、Tornado应用:自己有

总结

以上是编程之家为你收集整理的WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道全部内容,希望文章能够帮你解决WebSocket协议!是每个Python程序员都必懂的协议!别说你不知道所遇到的程序开发问题。


如果您也喜欢它,动动您的小指点个赞吧

除非注明,文章均由 laddyq.com 整理发布,欢迎转载。

转载请注明:
链接:http://laddyq.com
来源:laddyq.com
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


联系我
置顶