在Django中使⽤Channels功能
前⾔:最近后台写游戏更新版本功能,简单就是前端发送更新请求,后端需要对很多台服务器进⾏更新和各种操作,本来想着实现不难,后来发现因为后端需要执⾏很长时间,前端返回报错,后端会执⾏完毕,但是前端先断开了,这样在前端页⾯我就看不到更新结果了。通过调整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⽂档链接
adthedocs.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 = [
'ib.staticfiles',
... ...
'channels',
]
# 指定ASGI的路由地址
ASGI_APPLICATION = 'uting.application' #ASGI_APPLICATION 指定主路由的位置为webapp下的routing.py⽂件中的application
3.3.setting.py的同级⽬录下创建routing.py路由⽂件,routing.py类似于Django中的url.py指明websocket协议的路由
from channels.auth import AuthMiddlewareStack
uting import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
uting
application = ProtocolTypeRouter({
'websocket':AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(
)
)
)
})
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.scope类似于django中的request,包含了请求的type、path、header、cookie、session、user等等有⽤的信息
URLRouter:指定路由⽂件的路径,也可以直接将路由信息写在这⾥,代码中配置了路由⽂件的路径,会去对应应⽤下的routeing.py⽂件中查websocket_urlpatterns
uting.py内容如下
from django.urls import path
sumers 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应⽤。 
ic.websocket import WebsocketConsumer
ic.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/');
连接事件 
console.log(getCurrentDate(2) + ' ' + 'websocket connection success')
};
错误事件
前端websocket怎么用<(getCurrentDate(2) + ' ' + 'websocket connection error')
};
关闭事件
layer.msg('websocket关闭,检查错误⽇志', {icon: 2});
<(getCurrentDate(2) + ' ' + 'websocket closed unexpectedly 状态码:' + e.code);
chatSocket.close();
};
接收事件
var data = JSON.parse(e.data);
}
五、测试Channels功能     
总结:⾃从使⽤Websocket功能后,再也没发⽣前端突然断开的情况了,对于长时间运⾏的任务,使⽤websocket是不错的选择~,有不⾜的地⽅请多多指教 

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。