django使用channels2.x實(shí)現(xiàn)實(shí)時(shí)通訊
一、背景
在最近的項(xiàng)目中的一個(gè)需求是消息實(shí)時(shí)推送消息以及通知功能,項(xiàng)目使用django寫的所以決定采用django-channels來實(shí)現(xiàn)websocket進(jìn)行實(shí)時(shí)通訊。目前官方已經(jīng)更新到2.1版本,相對(duì)于老的channels 1.x版本有了很大變化,無論是使用方式還是功能,其中最大的變化莫過于2.x版本中帶來的asyncio特性,可使用異步處理模式。本文內(nèi)容將介紹channels2版本使用,由于項(xiàng)目django是1.11,其中也遇到了一些坑,比如在channels在處理一次請(qǐng)求后hang住然后報(bào)錯(cuò),后面修改了下django1.11版本的一點(diǎn)源碼得以解決,2.0版本應(yīng)該不會(huì)有問題。
二、channels介紹
channels是以django插件的形式存在,它不僅能處理http請(qǐng)求,還提供對(duì)websocket、MQTT等長(zhǎng)連接支持。不僅如此,channels在保留了原生django的同步和易用的特性上還帶來了異步處理方式(channels2.X版本),并且將django自帶的認(rèn)證系統(tǒng)以及session集成到模塊中,擴(kuò)展性非常強(qiáng)。官方文檔:https://channels.readthedocs.io/en/latest/index.html
三、安裝以及安裝需求
channels2.0最低django版本要求是1.11+,python3.5+。筆者的版本是django1.11,直接安裝可能有問題,以下是測(cè)試通過的版本。
筆者的相關(guān)版本如下:
Django==1.11.10 channels==2.1.4 channels-redis==2.3.1 asgiref==2.1.6 asgi-redis==1.4.3
如果django版本比較高直接采用pip安裝:
pip3 install channels pip3 install channels-redis #可選的,官方推薦如果使用redis作為channel layer
redis安裝可以參考博客:http://www.dbjr.com.cn/article/151522.htm
四、開始使用
一、配置settings.py
筆者采用的redis作為channel layer(關(guān)于其介紹請(qǐng)移步至https://channels.readthedocs.io/en/latest/topics/channel_layers.html),它是實(shí)現(xiàn)消息推送的核心,在項(xiàng)目的settings.py中:
注冊(cè)channles app:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'cmdb', 'channels', #注冊(cè)app ]
配置channels layer:
ASGI_APPLICATION = 'devops.routing.application' CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { "hosts": [('10.1.210.33', 6379)], #需修改 }, }, }
二、路由配置
在項(xiàng)目settings文件同級(jí)目錄中新增routing.py
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # Author:wd from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter import deploy.routing application = ProtocolTypeRouter({ 'websocket': AuthMiddlewareStack( URLRouter( deploy.routing.websocket_urlpatterns# 指明路由文件是devops/routing.py ) ), })
最后在app里配置路由和對(duì)應(yīng)的消費(fèi)者,筆者這里是devops下的routing.py:
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # Author:wd from django.conf.urls import url from . import consumers websocket_urlpatterns = [ url(r'^ws/deploy/(?P<service_name>[^/]+)/$', consumers.DeployResult), #consumers.DeployResult 是該路由的消費(fèi)者 ]
項(xiàng)目目錄結(jié)構(gòu)如下:
三、編寫webscoket消息處理方法(消費(fèi)者)
首先說明,消費(fèi)者是Channels代碼的基本單元,當(dāng)一個(gè)新的Socket進(jìn)入的時(shí)候,Channels會(huì)根據(jù)路由表找到正確的消費(fèi)者,以下代碼中每個(gè)方法都可以看作一個(gè)消費(fèi)者,他們消費(fèi)不同的event,比如剛剛接受連接時(shí)候connect方法進(jìn)行消費(fèi)處理并接受連接,關(guān)閉websocket時(shí)候使用disconnect進(jìn)行消費(fèi)處理。
deploy/consumers.py:
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # Author:wd from channels.generic.websocket import AsyncWebsocketConsumer import json class DeployResult(AsyncWebsocketConsumer): async def connect(self): self.service_uid = self.scope["url_route"]["kwargs"]["service_uid"] self.chat_group_name = 'chat_%s' % self.service_uid # 收到連接時(shí)候處理, await self.channel_layer.group_add( self.chat_group_name, self.channel_name ) await self.accept() async def disconnect(self, close_code): # 關(guān)閉channel時(shí)候處理 await self.channel_layer.group_discard( self.chat_group_name, self.channel_name ) # 收到消息 async def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] print("收到消息--》",message) # 發(fā)送消息到組 await self.channel_layer.group_send( self.chat_group_name, { 'type': 'client.message', 'message': message } ) # 處理客戶端發(fā)來的消息 async def client_message(self, event): message = event['message'] print("發(fā)送消息。。。",message) # 發(fā)送消息到 WebSocket await self.send(text_data=json.dumps({ 'message': message }))
以上代碼部分說明:
1.self.scope是單個(gè)連接傳入的詳細(xì)信息,其中包含了請(qǐng)求的session、以及django認(rèn)證系統(tǒng)中的用戶信息等;
2.async...await 是python3.5之后的新異步特性,基于asyncio模塊;
四、發(fā)起webscoket請(qǐng)求
利用js發(fā)起websocket請(qǐng)求
function InitWebSocket() { var websocket = new WebSocket( 'ws://' + window.location.host + '/ws/deploy/tasks/' ); websocket.onmessage = function (e) { var data = JSON.parse(e.data); var message = '\n' + data['message']; document.querySelector('#deploy-res').innerText += (message + '\n'); }; }
五、發(fā)送消息到channel
無論是消息的推送或者消息的接受,都是經(jīng)過channel layer進(jìn)行傳輸,以下是發(fā)送消息示例,
from channels.layers import get_channel_layer from asgiref.sync import async_to_sync channel_layer = get_channel_layer() def send_channel_msg(channel_name, msg): """ send msg to channel :param channel_name: :param msg: :return: """ async_to_sync(channel_layer.group_send)(channel_name, {"type": "deploy.run", "text": msg})
六、生產(chǎn)部署
大多數(shù)django的應(yīng)用部署方式都采用的是nginx+uwsgi進(jìn)行部署,當(dāng)django集成channels時(shí)候,由于uwsgi不能處理websocket請(qǐng)求,所以我們需要asgi服務(wù)器來處理websocket請(qǐng)求,官方推薦使用daphne。下一篇文章將介紹nginx+supervisor+daphne+uwsgi進(jìn)行生產(chǎn)部署。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Django實(shí)現(xiàn)WebSocket在線聊天室功能(channels庫)
- Django中如何使用Channels功能
- Django使用channels + websocket打造在線聊天室
- django使用channels實(shí)現(xiàn)通信的示例
- 淺談django channels 路由誤導(dǎo)
- 詳解Django-channels 實(shí)現(xiàn)WebSocket實(shí)例
- Django使用Channels實(shí)現(xiàn)WebSocket的方法
- Django Channels 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)實(shí)時(shí)聊天和消息推送功能
- django channels使用和配置及實(shí)現(xiàn)群聊
相關(guān)文章
簡(jiǎn)單實(shí)現(xiàn)一個(gè)vue公式編輯器組件demo
這篇文章主要介紹了輕松實(shí)現(xiàn)一個(gè)簡(jiǎn)單的vue公式編輯器組件示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01vue-router的beforeRouteUpdate不觸發(fā)問題
這篇文章主要介紹了vue-router的beforeRouteUpdate不觸發(fā)問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04如何優(yōu)雅的在一臺(tái)vps(云主機(jī))上面部署vue+mongodb+express項(xiàng)目
這篇文章主要介紹了如何優(yōu)雅的在一臺(tái)vps(云主機(jī))上面部署vue+mongodb+express項(xiàng)目,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01基于VUE移動(dòng)音樂WEBAPP跨域請(qǐng)求失敗的解決方法
這篇文章主要介紹了基于VUE移動(dòng)音樂WEBAPP跨域請(qǐng)求失敗的解決方法,需要的朋友可以參考下2018-01-01Vue登錄后添加動(dòng)態(tài)路由并跳轉(zhuǎn)的實(shí)踐分享
這篇文章講給大家詳細(xì)介紹一下Vue如何實(shí)現(xiàn)登錄后添加動(dòng)態(tài)路由并跳轉(zhuǎn),文章通過代碼示例介紹的非常詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的的幫助,需要的朋友可以參考下2023-07-07vue中provide和inject的用法及說明(vue組件爺孫傳值)
這篇文章主要介紹了vue中provide和inject的用法及說明(vue組件爺孫傳值),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05