前言:最近后台写游戏更新版本功能,简单就是前端发送更新请求,后端需要对很多台服务器进行更新和各种操作,本来想着实现不难,后来发现因为后端需要执行很长时间,前端返回报错,后端会执行完毕,但是前端先断开了,这样在前端页面我就看不到更新结果了。通过调整nginx参数,设置超时时间,还是日志会报499状态码错误。后来了解到了websocket,对于需要长时间处理的请求,使用websocket会更好,通过使用websocket实现了自己的功能,简单分享下

一、什么是WebSocket

WebSocket是一种在单个TCP连接上进行全双工通讯的协议。WebSocket允许服务端主动向客户端推送数据。
在WebSocket协议中,客户端浏览器和服务器只需要完成一次握手就可以创建持久性的连接,并在浏览器和服务器之间进行双向的数据传输。

WebSocket的响应头中重要的字段:
HTTP/1.1 101 Swi tching Protocols:切换协议,WebSocket协议通过HTTP协议来建立运输层的TCP连接
Connection和Upgrade:表示服务端发起的WebSocket响应
Sec-WebSocket-Accept:表示服务器接受了客户端的请求,由Sec-WebSocket-Key计算得来

WebSocket协议的优点:
支持双向通信,实时性更强
数据格式比较轻量,性能开销小,通信高效
支持扩展,用户可以扩展协议或者实现自定义的子协议(比如支持自定义压缩算法等)

WebSocket协议的缺点:
少部分浏览器不支持,浏览器支持的程度与方式有区别
长连接对后端处理业务的代码稳定性要求更高,后端推送功能相对复杂
成熟的HTTP生态下有大量的组件可以复用,WebSocket较少

WebSocket的应用场景:
即时聊天通信,网站消息通知
在线协同编辑,如腾讯文档
多玩家在线游戏,视频弹幕,股票基金实施报价

二、什么是Channels

Django本身不支持WebSocket,但可以通过集成Channels框架来实现WebSocket
Channels是针对Django项目的一个增强框架,可以使Django不仅支持HTTP协议,还能支持WebSocket,MQTT等多种协议,同时Channels还整合了Django的auth以及session系统方便进行用户管理及认证。

2.1channels文件和配置的含义
asgi.py:介于网络协议服务和Python应用之间的接口,能够处理多种通用协议类型,包括HTTP、HTTP2和WebSocket
channel_layers:在settings.py中配置。类似于一个通道,发送者(producer)在一段发送消息,消费者(consumer)在另一端进行监听
routings.py:相当于Django中的urls.py
consumers.py:相当于Django中的views.py

2.2channels文档链接

https://channels.readthedocs.io/en/latest/introduction.html

2.3.WSGI和ASGI不同

WSGI(Python Web Server Gateway Interface):为Python语言定义的Web服务器和Web应用程序或者框架之间的一种简单而通用的接口。

ASGI(Asynchronous Web Server Gateway Interface):异步网关协议接口,一个介于网络协议服务和Python应用之间的标准接口,能够处理多种通用的协议类型,包括HTTP,HTTP2和WebSocket。

三、Django中使用Channel

3.1安装channels

pip install channels==2.1.7

3.2修改setting.py文件

INSTALLED_APPS = [
'django.contrib.staticfiles',
... ...
'channels',
] # 指定ASGI的路由地址
ASGI_APPLICATION = 'webapp.routing.application' #ASGI_APPLICATION 指定主路由的位置为webapp下的routing.py文件中的application

3.3.setting.py的同级目录下创建routing.py路由文件,routing.py类似于Django中的url.py指明websocket协议的路由

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
import webapp.routing application = ProtocolTypeRouter({
'websocket':AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(
webapp.routing.websocket_urlpatterns
)
)
)
})

ProtocolTypeRouter:ASGI支持多种不同的协议,在这里可以指定特定协议的路由信息,这里只使用了websocket协议,这里只配置websocket即可
AllowedHostsOriginValidator:指定允许访问的IP,设置后会去Django中的settings.py中去查找ALLOWED_HOSTS设置的IP
AuthMiddlewareStack:用于WebSocket认证,继承了Cookie Middleware,SessionMiddleware,SessionMiddleware。
django的channels封装了django的auth模块,使用这个配置我们就可以在consumer中通过下边的代码获取到用户的信息,和请求的url路径

def connect(self):
self.user = self.scope["user"]
self.request_url = self.scope['path']

self.scope类似于django中的request,包含了请求的type、path、header、cookie、session、user等等有用的信息
URLRouter: 指定路由文件的路径,也可以直接将路由信息写在这里,代码中配置了路由文件的路径,会去对应应用下的routeing.py文件中查找websocket_urlpatterns

3.4webapp.routing.py内容如下

from django.urls import path
from webapp.consumers import ChatConsumer websocket_urlpatterns = [
  path('ws/chat/',ChatConsumer)
]

routing.py路由文件跟django的url.py功能类似,语法也一样,意思就是访问ws/chat/都交给ChatConsumer处理。  

3.5在要使用WebSocket的应用中创建consumers.py,consumers.py是用来开发ASGI接口规范的python应用,而Django中的view.py是用来开发符合WSGI接口规范的python应用。  

from channels.generic.websocket import WebsocketConsumer
from channels.generic.websocket import AsyncWebsocketConsumer
import json,time

Channels支持同步,也支持异步方式

同步方式代码如下:

class ChatConsumer(WebsocketConsumer):
# websocket建立连接时执行方法
def connect(self):
self.accept() # websocket断开时执行方法
def disconnect(self, close_code):
self.close() # 从websocket接收到消息时执行函数
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = f'结果:{text_data_json}'
self.send(text_data=json.dumps(
{
'message': message
}))

异步方式代码如下:

class ChatConsumer(AsyncWebsocketConsumer):
#websocket建立连接时执行方法
async def connect(self):
await self.accept() # websocket断开时执行方法
async def disconnect(self, close_code):
print(close_code) # 从websocket接收到消息时执行函数
async def receive(self, text_data):
for i in range(10):
time.sleep(i)
message = '结果: ' + str(i)
await self.send(text_data=json.dumps({
'message': message
})
)

需要注意的是在异步中所有的逻辑都应该是异步的,不可以那同步的和异步的代码混合使用。  

四、前端Websocket使用

WebSocket对象一个支持四个消息:onopen,onmessage,oncluse和onerror

onopen: 当浏览器和websocket服务端连接成功后会触发onopen消息
onerror: 如果连接失败,或者发送、接收数据失败,或者数据处理出错都会触发onerror消息
onmessage: 当浏览器接收到websocket服务器发送过来的数据时,就会触发onmessage消息,参数e包含了服务端发送过来的数据
onclose: 当浏览器接收到websocket服务器发送过来的关闭连接请求时,会触发onclose消息

拼接websocket请求地址,建立长连接

var chatSocket = new WebSocket('ws://' + window.location.host + '/ws/ver_update/');

连接事件  

chatSocket.onopen = function () {
console.log(getCurrentDate(2) + ' ' + 'websocket connection success')
};

错误事件

chatSocket.onerror = function () {
console.error(getCurrentDate(2) + ' ' + 'websocket connection error')
};

关闭事件

chatSocket.onclose = function (e) {
layer.msg('websocket关闭,检查错误日志', {icon: 2});
console.error(getCurrentDate(2) + ' ' + 'websocket closed unexpectedly 状态码:' + e.code);
chatSocket.close();
};

接收事件

chatSocket.onmessage = function (e) {
var data = JSON.parse(e.data);
}

五、测试Channels功能      

总结:自从使用Websocket功能后,再也没发生前端突然断开的情况了,对于长时间运行的任务,使用websocket是不错的选择~,有不足的地方请多多指教  

在Django中使用Channels功能的更多相关文章

  1. Django中组合搜索功能

    需求分析 很多电商网站中有组合搜索的功能,所谓组合搜索就是网页中组合多个条件,对数据库中进行查询,并且将结果显示在页面中,看个例子吧: 注意红框中的标识,我们可以根据URL来做组合搜索. video- ...

  2. django中添加日志功能

    官方文档 猛戳这里 在settings中配置以下代码 #LOGGING_DIR 日志文件存放目录 LOGGING_DIR = "logs" # 日志存放路径 if not os.p ...

  3. django中如何实现分页功能

    1.在html页面中导入js文件和css文件 <link rel="stylesheet" href="../../../static/css/jquery.pag ...

  4. Django中的信号

    信号 Django 提供一个“信号分发器”,允许解耦的应用在框架的其它地方发生操作时会被通知到. 简单来说,信号允许特定的sender通知一组receiver某些操作已经发生. 这在多处代码和同一事件 ...

  5. Django中使用Celery

    一.前言 Celery是一个基于python开发的分布式任务队列,如果不了解请阅读笔者上一篇博文Celery入门与进阶,而做python WEB开发最为流行的框架莫属Django,但是Django的请 ...

  6. django中使用事务以及接入支付宝支付功能

    之前一直想记录一下在项目中使用到的事务以及支付宝支付功能,自己一直犯懒没有完,趁今天有点兴致,在这记录一下. 商城项目必备的就是支付订单的功能,所以就会涉及到订单的保存以及支付接口的引入.先来看看订单 ...

  7. Django 中自定义用户模型及集成认证授权功能总结

    1. 概述 Django 中的 django.contrib.auth 应用提供了完整的用户及认证授权功能. Django 官方推荐基于内置 User 数据模型创建新的自定义用户模型,方便添加 bir ...

  8. django中tinymce添加图片上传功能

    主要参考以下: https://pixabay.com/en/blog/posts/direct-image-uploads-in-tinymce-4-42/ http://blog.csdn.net ...

  9. Django中使用ModelForm实现Admin功能

    接上一篇<Django中使用Bootstrap> ModelForm 可以将数据库中的信息展示在一个表中,因此我们在查询数据库信息时可以使用ModelForm在前端展示查询到的信息. 在上 ...

随机推荐

  1. 数据源连接数据库配置相关xml文件

    学完数据源连接数据后,做个笔记,当我们的程序对数据库访问频繁时,为了提高程序运行效率,我们可以通过 数据源连接数据库,从数据库连接池中直接取得出于空闲状态的数据库连接对象,以下是相关xml文件的配置: ...

  2. .NET 6 Preview 6 正式发布: 关注网络开发

    微软.NET 团队的项目经理在博客上发布了.NET 6 Preview 6,  在候选发布阶段之前的倒数第二个预览版,也就是8月份还会发布一个Preview 7,9月份开始进入RC,两个候选版本将专注 ...

  3. 深入理解Java多线程——ThreadLocal

    目录 定义 API 场景分析 场景实验,观察Spring框架在多线程场景的执行情况 10000此请求,单线程 10000次请求,线程数加到100 对c的访问加锁 把c设为ThreadLocal 收集多 ...

  4. java001-泛型

    泛型出现的意义: 为编码阶段的不确定性和转化做视觉设计 将运行期遇到的问题转移到编译期,省去了强转的麻烦 package com.xiaolin.basic; /** * 泛型:将运行期遇到的问题转移 ...

  5. python得到当前版本号

    import sys print(sys.winver) 3.7 # 导入sys模块的argv,winver成员,并为其指定别名v.wv from sys import argv as v, winv ...

  6. SpringBoot获取前端传递JSON的几种方法

    一.Json对象+@RequestBody接收 var val = {id: 1, name: "小明"}; $.ajax({ url: "/getJson", ...

  7. 痞子衡嵌入式:了解i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择. 关于 i.MXRT 系列 BootROM 中串行 NOR ...

  8. python -- namedtuple元组

  9. python + mysql 实现表更新数据

    实例如下: import pymysqldef Update_Set(): #打开数据库链接 db = pymysql.connect("localhost","root ...

  10. 公有云上构建云原生 AI 平台的探索与实践 - GOTC 技术论坛分享回顾

    7 月 9 日,GOTC 2021 全球开源技术峰会上海站与 WAIC 世界人工智能大会共同举办,峰会聚焦 AI 与云原生两大以开源驱动的前沿技术领域,邀请国家级研究机构与顶级互联网公司的一线技术专家 ...