django之websocket(基於redis服務器與Channels實現)

1、Channels介紹

Channels改變Django在下面和經過Django的同步核心編織異步代碼,容許Django項目不只處理HTTP,還須要處理須要長時間鏈接的協議 - WebSockets,MQTT,chatbots,amateur radio等等。python

它在保留Django同步和易用性的同時實現了這一點,容許您選擇編寫代碼的方式 - 以Django視圖,徹底異步或二者混合的方式同步。除此以外,它還提供了與Django的auth系統,會話系統等的集成,能夠比以往更輕鬆地將僅HTTP項目擴展到其餘協議。web

它還將此事件驅動架構與通道層捆綁在一塊兒,該系統容許在流程之間輕鬆通訊,並將項目分紅不一樣的流程。redis

Channels提供了編寫基本消費者的工具- 能夠處理聊天消息或通知的各個部分 - 並將它們與URL路由,協議檢測和其餘便利的東西聯繫在一塊兒,以製做完整的應用程序。docker

傳統的Django視圖仍然存在於Channels而且仍然可用,它們被封裝在一個名爲的ASGI應用程序中(ASGI是構建Channels的異步服務器規範的名稱。與WSGI同樣,它旨在不​​同的服務器和框架之間進行選擇,而不是被鎖定在Channels和服務器Daphne中。django

2、Channels的使用

1.集成Channels庫

1)爲Channels建立根路由配置(在項目文件中建立routing.py)json

from channels.routing import ProtocolTypeRouter application = ProtocolTypeRouter({ # (http->django views is added by default)
})

2)將Channels註冊到settings.py INSTALLED_APPS中服務器

3)在根路由配置中指向Channels,settings.py中添加websocket

ASGI_APPLICATION = 'object.routing.application'

Channels服務器的運行架構

python manage.py runserver
#若是運行成功,顯示
#Starting ASGI/Channels development server at http://127.0.0.1:8000/

2.消費者的編寫

當Django接受HTTP請求時,它會查詢根URLconf以查找視圖函數,而後調用視圖函數來處理請求。相似地,當Channels接受WebSocket鏈接時,它會查詢根路由配置以查找使用者,而後調用使用者的各類函數來處理來自鏈接的事件。app

1)app中建立文件routing.py,編寫路由處理websocket請求

from django.conf.urls import url from . import consumers websocket_urlpatterns = [ url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer), ]

2)app中建立文件consumers.py,編寫處理websocket腳本

from asgiref.sync import async_to_sync from channels.generic.websocket import WebsocketConsumer import json class ChatConsumer(WebsocketConsumer): def connect(self): self.room_name = self.scope['url_route']['kwargs']['room_name'] self.room_group_name = 'chat_%s' % self.room_name # Join room group
 async_to_sync(self.channel_layer.group_add)( self.room_group_name, self.channel_name ) self.accept() def disconnect(self, close_code): # Leave room group
 async_to_sync(self.channel_layer.group_discard)( self.room_group_name, self.channel_name ) # Receive message from WebSocket
    def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] # Send message to room group
 async_to_sync(self.channel_layer.group_send)( self.room_group_name, { 'type': 'chat_message', 'message': message } ) # Receive message from room group
    def chat_message(self, event): message = event['message'] # Send message to WebSocket
        self.send(text_data=json.dumps({ 'message': message }))
consumers.py

3)將app路由註冊到根路由中

from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter import chat.routing application = ProtocolTypeRouter({ # (http->django views is added by default)
    'websocket': AuthMiddlewareStack( URLRouter( chat.routing.websocket_urlpatterns ) ), })

3.channel layer的啓用

channel layer是一種通訊系統。它容許多個消費者實例彼此交談,以及與Django的其餘部分交談。

channel layer提供如下抽象:

  • channel是其中消息能夠被髮送到一個郵箱。每一個channel都有一個名字。擁有channel名稱的任何人均可以向channel發送消息。
  • group是一組相關的渠道。一個group有一個名字。具備group名稱的任何人均可以按名稱向group添加/刪除頻道,並向組中的全部頻道發送消息。

使用一個使用Redis做爲其後備存儲的通道層。要在端口6379上啓動Redis服務器

settings.py中添加

CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { "hosts": [('127.0.0.1', 6379)], }, }, }

而後使用docker開啓redis

docker run -p 6379:6379 -d redis:版本號

 4.消費者的異步

將消費者處理腳本重寫爲異步

from channels.generic.websocket import AsyncWebsocketConsumer import json class ChatConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_name = self.scope['url_route']['kwargs']['room_name'] self.room_group_name = 'chat_%s' % self.room_name # Join room group
 await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.accept() async def disconnect(self, close_code): # Leave room group
 await self.channel_layer.group_discard( self.room_group_name, self.channel_name ) # Receive message from WebSocket
    async def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] # Send message to room group
 await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat_message', 'message': message } ) # Receive message from room group
    async def chat_message(self, event): message = event['message'] # Send message to WebSocket
        await self.send(text_data=json.dumps({ 'message': message }))
consumers.py

異步使用者能夠提供更高級別的性能,由於他們在處理請求時不須要建立其餘線程。

這個新代碼用於ChatConsumer與原始代碼很是類似,但有如下區別:

  • ChatConsumer如今繼承AsyncWebsocketConsumer而不是 WebsocketConsumer
  • 全部方法 由async def定義
  • await 用於調用執行I / O的異步函數。
  • async_to_sync 在通道層上調用方法時再也不須要它。
相關文章
相關標籤/搜索