websocket的应用---Django
websocket的应用---Django
1.长轮询
轮询:在前端通过写js实现。缺点:有延迟、服务器压力大。
就是客户端通过一定的时间间隔以频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步。问题很明显,当客户端以固定频率向服务器端发送请求时,服务器端的数据可能并没有更新,带来很多无谓请求,浪费带宽,效率低下。
长轮询
首先需要为每个用户维护一个队列,用户浏览器会通过js递归向后端自己的队列获取数据,自己队列没有数据,会将请求夯住(去队列中获取数据),夯一段时间之后再返回。
注意:一旦有数据立即获取,获取到数据之后会再发送请求。
用户发来请求之后,最多会夯住N秒(30s),因为有消息的时候回立即返回,没有消息时才最多夯N秒。
2.websocket
2.1 原理
- WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
- WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
- WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。
2.2具体实现:
客户端向服务端发送随机字符串,在http的请求头中
Sec-WebSocket-Key
服务端接受到到随机字符串
- 随机字符串 + 魔法字符串
- sha1加密
- base64加密
- 放在响应头中给用户返回
Sec-WebSocket-Accept
客户端浏览器会进行校验,校验不通过:服务端不支持websocket协议。
客户端和服务端进行相互收发消息,数据加密和解密。
解密细节:
获取第二个字节的后7位,payload len
判断payload len的值
= 127
2字节 + 8字节 + 4字节 + 数据
= 126
2字节 + 2字节 + 4字节 + 数据
<= 125
2字节 + 4字节 + 数据
使用masking key 对数据进行解密
2.3 手动创建支持websocket的服务端(理解)
服务端
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('\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()
return header_dict 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 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()
# 握手环节
header_dict = get_headers(conn.recv(1024))
# 公认的魔法字符串(固定)
magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' random_string = header_dict['Sec-WebSocket-Key']
value = random_string + magic_string
ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
# 给前端发送的响应数据
response = "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://127.0.0.1:8002\r\n\r\n" response = response %ac.decode('utf-8') conn.send(response.encode('utf-8')) # 接受数据
while True:
data = conn.recv(1024)
msg = get_data(data)
print(msg)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="开始" onclick="startConnect();"> <script>
var ws = null;
function startConnect() {
// 1. 内部会先发送随机字符串
// 2. 内部会校验加密字符串
ws = new WebSocket('ws://127.0.0.1:8002')
}
</script>
</body>
</html>
2.4 企业应用
我们学过django和flask框架,内部基于wsgi做的socket,默认他俩都不支持websocket协议,只支持http协议。
flask中应用
pip3 install gevent-websocket
django中应用
pip3 install channels
请保留2个案例(django):
在基于Django实现的时候因为需要导入channels
模块,会跟Django中的wsgiref
发生冲突所以需要在配置文件中添加配置:
1.首先是在settings文件中的需要注册这个应用:
INSTALLED_APPS = ['channels']
2.在settings文件中增加一个文件的路径:
ASGI_APPLICATION = "wechat.routing.application"
这个文件是用来写前端使用websocket发送数据时指定的接收路径,相当于url;
1v1示例
接收数据的url
from channels.routing import ProtocolTypeRouter, URLRouter
from django.conf.urls import url
from app01 import consumers application = ProtocolTypeRouter({
'websocket': URLRouter([
url(r'^x1/$', consumers.ChatConsumer),
])
})
内部处理的数据的代码:
from channels.exceptions import StopConsumer
from channels.generic.websocket import WebsocketConsumer class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
""" websocket连接到来时,自动执行 """
print('有人来了')
self.accept() def websocket_receive(self, message):
""" websocket浏览器给发消息时,自动触发此方法 """
print('接收到消息', message) self.send(text_data='收到了') # self.close() def websocket_disconnect(self, message):
print('客户端主动断开连接了')
raise StopConsumer()
前端操作的代码:
<script>
# 指定一个变量
var ws; # 当加载页面时自动执行
$(function () {
# 执行函数
initWebSocket();
}); function initWebSocket() {
# 与后端的websocket建立连接,创建一个对象
ws = new WebSocket("ws://127.0.0.1:8000/x1/"); # 成功得到时候自动触发这个方法
ws.onopen = function(){
$('#tips').text('连接成功');
}; # 接收到消息的时候自动触发这个方法;
ws.onmessage = function (arg) {
var tag = document.createElement('div');
tag.innerHTML = arg.data;
$('#content').append(tag);
}; # 服务端断开连接客户端也断开
ws.onclose = function () {
ws.close();
}
}
# 向服务端发送数据,使用创建的ws对象.send方就可以发送数据
function sendMessage() {
ws.send($('#txt').val());
}
</script>
n v n 示例
- 在routing文件中的代码:前端websocket发送数据的路径
from channels.routing import ProtocolTypeRouter, URLRouter
from django.conf.urls import url
from app01 import consumers
application = ProtocolTypeRouter({
'websocket': URLRouter([
url(r'^x1/$', consumers.ChatConsumer),
])
})
# 这个文件写的是和前端websocket创建连接的路径,
在consumers文件中的代码:websocket的模块应用
这里主要是接收数据对数据进行一个处理
from channels.exceptions import StopConsumer
from channels.generic.websocket import WebsocketConsumer
from asgiref.sync import async_to_sync
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
""" websocket连接到来时,自动执行 """
print('有人来了')
# 里边的'22922192'字符串是随意指定的,相当于一个标识;
async_to_sync(self.channel_layer.group_add)('22922192', self.channel_name)
self.accept()
def websocket_receive(self, message):
""" websocket浏览器给发消息时,自动触发此方法 """
print('接收到消息', message)
# 接收到消息 {'type': 'websocket.receive', 'text': 'fdsfsdfafd'}
async_to_sync(self.channel_layer.group_send)('22922192', {
# 这个是指定函数执行
'type': 'xxx.ooo',
# 将获取到的消息
'message': message['text']
})
def xxx_ooo(self, event):
# 触发这个方法的时候就将消息发出
message = event['message']
self.send(message)
def websocket_disconnect(self, message):
""" 断开连接 """
print('客户端主动断开连接了')
async_to_sync(self.channel_layer.group_discard)('22922192', self.channel_name)
raise StopConsumer()
另一种websocket的写法
class NewChatConsumer(WebsocketConsumer):
def connect(self):
print('有人来了')
async_to_sync(self.channel_layer.group_add)('22922192', self.channel_name)
self.accept()
def receive(self, text_data=None, bytes_data=None):
print('接收到消息', text_data)
async_to_sync(self.channel_layer.group_send)('22922192', {
'type': 'xxx.ooo',
'message': text_data
})
def xxx_ooo(self, event):
message = event['message']
self.send(message)
def disconnect(self, code):
print('客户端主动断开连接了')
async_to_sync(self.channel_layer.group_discard)('22922192', self.channel_name)
其实都是一样的,只是这个源码内部是多了几步的调用,而这种写法是将调用的步骤省去;
- 前端websocket的写法:
<script>
# 指定一个变量
var ws;
# 当加载页面时自动执行
$(function () {
# 执行函数
initWebSocket();
});
function initWebSocket() {
# 与后端的websocket建立连接,创建一个对象
ws = new WebSocket("ws://127.0.0.1:8000/x1/");
# 成功得到时候自动触发这个方法
ws.onopen = function(){
$('#tips').text('连接成功');
};
# 接收到消息的时候自动触发这个方法;
ws.onmessage = function (arg) {
var tag = document.createElement('div');
tag.innerHTML = arg.data;
$('#content').append(tag);
};
# 服务端断开连接客户端也断开
ws.onclose = function () {
ws.close();
}
}
# 向服务端发送数据,使用创建的ws对象.send方就可以发送数据
function sendMessage() {
ws.send($('#txt').val());
}
</script>
https://www.cnblogs.com/zhufanyu/p/11951654.html
websocket的应用---Django的更多相关文章
- vue+django实现websocket连接
一.概述 在项目中,需要使用websocket,来展示一些实时信息. 这里使用django 3.1.5 二.django项目 安装模块 pip3 install django-cors-headers ...
- django面试题
1. 对Django的认识? #1.Django是走大而全的方向,它最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构.以及全功能的管理后台. #2.D ...
- Django 的认识,面试题
Django 的认识,面试题 1. 对Django的认识? #1.Django是走大而全的方向,它最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构.以及全 ...
- django面试八
1. 对Django的认识? #1.Django是走大而全的方向,它最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构.以及全功能的管理后台. #2.Dja ...
- Django 的认识,题型
Django 的认识,面试题 链接:https://www.cnblogs.com/chongdongxiaoyu/p/9403399.html 1. 对Django的认识? #1.Django是走大 ...
- 【翻译】Django Channels 官方文档 -- Tutorial
Django Channels 官方文档 https://channels.readthedocs.io/en/latest/index.html 前言: 最近课程设计需要用到 WebSocket,而 ...
- Django实现WebSSH操作物理机或虚拟机
我想用它替换掉xshell.crt之类的工具 WebSSH操作物理机或虚拟机 Django实现WebSSH操作Kubernetes Pod文章发布后,有小伙伴说咖啡哥,我们现在还没有用上Kuberne ...
- Django常用知识整理
Django 的认识,面试题 1. 对Django的认识? #1.Django是走大而全的方向,它最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构.以及全 ...
- django考点
django考点 1 列举Http请求中常见的请求方式2 谈谈你对HTTP协议的认识.1.1 长连接3 简述MVC模式和MVT模式4 简述Django请求生命周期5 简述什么是FBV和CBV6 谈一谈 ...
随机推荐
- Kafka高性能的原理
Kafka高性能的原理 高性能,高并发,高可用 使用了NIO技术.高并发. 顺序读写.硬盘的顺序读写性能要高于内存的随机读写. 跳表设计. 稀疏索引.index文件里面有部分offset的位置. 使用 ...
- SQL注入-DNS注入(一)
这篇文章相对来说比较入门,参考的文章是:https://www.jianshu.com/p/c805209244c2 0x00前言 前段时间在做盲注 分别是基于时间和基于布尔型的 说真的 这两种盲注真 ...
- FFmpeg 初级使用
ffmpeg来处理多种媒体文件,对帧进行操作的时候非常的复杂,下面介绍下使用FFmpeg对视频文件的操作. 1,安装 windows安装ffmpeg: 下载ffmpeg文件解压文件到c盘配置环境变量C ...
- 【进程/作业】篇章一:Linux进程及其管理(进程的管理基础)
概述:监控系统各方面的性能,保障各类服务的有序运行,是运维工作的重要组成部分,本篇就介绍一次常用的系统监控命令和相关的参数说明 具体包含以下几部分: 1.进程的管理基础 ,主要是讲一下概念性的东西 2 ...
- 浅谈 WebRTC 的 Audio 在进入 Encoder 之前的处理流程
在 WebRTC 中,Audio 数据在被送入编码器之前,有 2 大部分需要特别关注,一是数据采集,二是 Audio Processing. 作者:方来,技术专家,从事 voip 应用开发. 数据采集 ...
- 在jsp页面动态添加,删除文本框模块
jsp代码============ <table class="crud-content-info" > <tr > <td align=" ...
- [数据库]000 - 🍳Sysbench 数据库压力测试工具
000 - Sysbench 数据库压力测试工具 sysbench 是一个开源的.模块化的.跨平台的多线程性能测试工具,可以用来进行CPU.内存.磁盘I/O.线程.数据库的性能测试.目前支持的数据库有 ...
- 【探索之路】机器人篇(1)-ROS-mwRobot开篇
机器人的定义 首先,什么才是机器人?机器人是不是必须和人一样的外形?我们先看一看维基百科给机器人的定义: 由上可见,机器人并不是和人一样的外形,而是可以模拟人类行为或者思想再或者是模拟其他生物的机械. ...
- 人脸识别--SeetaFace
检测:http://download.csdn.net/detail/qq_14845119/9639840 对齐:http://download.csdn.net/detail/qq_1484511 ...
- Java学习日报7.17
控制台运行