`

Django Channels 原理

阅读更多

      Django Channels 是一个为 Django 提供异步扩展的库,通常主要用来提供 WebSocket 支持和后台任务。

原理

它的原理是将 Django 分为 2 种进程类型:

  • 一个用于处理 HTTP 和 WebSocket 的协议服务
  • 一个用于运行视图、WebSocket handler 以及后台任务的 worker 服务

两者通过 ASGI 协议通信,类似与 WSGI 但是运行在网络层上,并且支持更多协议。

Django Channels 并没有引入 asyncid、gevent 或者其它异步库,所有业务逻辑都在同一个业务进程/线程中同步运行。

细节请阅读 Django Channels docs/concepts

前提

想要运行 Django Channels 首先需要一个 ASGI 服务器,比如 Daphne,使用 Django worker 服务器运行:./manage.py runworker,以及 ASGI 请求的通道服务,比如 Redis。

即使启用 channels,所有的 HTTP 请求依旧是默认经过 Django 视图系统,因此可以无缝迁移过来。

好处

  • 易用的支持数以千计客户端的 HTTP long-poll 支持
  • 类似 Django 原生的 WebSocket 的会话和验证支持
  • 自动根据 cookie 为 WebSocket 提供登录
  • 大量事件触发底层支持
  • 0 宕机部署支持
  • 特定 URL 的底层 HTTP 控制
  • 可扩展支持其它协议或者事件源(例如 WebRTC、UDP、SMS)
  • Django 的官方支持

基本概念

channel

Django Channels 的核心数据解构叫做 channel,它是一个有序的 FIFO 队列,支持信息过期,对于一个监听器至多投递一次。类似于任务队列──信息由 producer 投递至 channel,并设置一个 consumer 监听该 channel。

注意消息投递是至多一次,因此遇到应用崩溃等情况会导致消息丢失。

Django Channels 的理念和 Go 语言内置的 channel 概念类似,不同之处在于 Django Channels 是网络透明的,因此 producer 和 consumer 通信可以穿越不同机器。在同一个网络中,Django Channels 的频道是根据名称属性区分的,如果你向一个名为 http.request 的 channel 发送信息,都是发送向同一个 channel。而对于不同网络中则不一样,channel 是网络隔离的。

consumer

“consumer”(消费者)是 channels 架构中处理请求的部分,和 Django 有 view 函数和 ViewClass 一样,consumer 也支持类式写法。例如你要处理 WebSocket 请求,可以实现一个 WebsocketConsumer 的子类,并通过 route_class 函数将该 consumer 与 URL 连接起来。

consumer 函数

consumer 类

from channels.generic.websockets import WebsocketConsumer

class MyConsumer(WebsocketConsumer):
    http_user = True         # 设置为 ``True`` 将会自动从 HTTP cookie 中登录用户,因此可以省去 channel_session_user 的设置。
    strict_ordering = False  # 默认设置

    def connection_groups(self, **kw):
        """返回 group 列表,并自动将本连接插入其中活删除
        """
        return ['test']

    def connect(self, message, **kw):
        """连接开始
        """
        self.message.reply_channel.send({'accept': True})

    def receive(self, text=None, bytes=None, **kw):
        """接收到信息时调用的函数
        """
        self.send(text=text, bytes=bytes)  # 将信息原封不动地返回

    def disconnect(self, message, **kw):
        """断开连接时将会被调用
        """
        pass

JsonWebsocketConsumer

from channels.generic.websockets import JsonWebsocketConsumer

class MyConsumer(JsonWebsocketConsumer):
    """使用与 WebsocketConsumer 基本一致
    """
    def receive(self, content, **kwargs):
        """这里的 content 会是 JSON 解码后的 Python 对象
        """
        self.send(content)

    # JsonWebsocketConsumer 实际上在接收到信息后调用了下面的方法,你也可以重载它们来调用自己的 JSON 编、解码器
    # @classmethod
    # def decode_json(cls, text):
    #     return my_custom_json_decoder(text)
    #
    # @classmethod
    # def encode_json(cls, content):
    #     return my_custom_json_encoder(content)

多通道 WebSocket

channels 还支持多个数据复用同一个 WebSocket,只需要使用 Demultiplexer 来分流。

from channels.generic.websockets import WebsocketDemultiplexer, JsonWebsocketConsumer

class EchoConsumer(JsonWebsocketConsumer):
    def connect(self, message, multiplexer, **kwargs):
        # 通过 multiplexer 发送消息
        multiplexer.send({"status": "I just connected!"})

    def disconnect(self, message, multiplexer, **kwargs):
        print("Stream %s is closed" % multiplexer.stream)

    def receive(self, content, multiplexer, **kwargs):
        multiplexer.send({"original_message": content})  # 原封不动地返回消息

class AnotherConsumer(JsonWebsocketConsumer):
    def receive(self, content, multiplexer=None, **kwargs):
        # 你的实现
        pass

class Demultiplexer(WebsocketDemultiplexer):
    # Wire your JSON consumers here: {stream_name : consumer}
    consumers = {
        "echo": EchoConsumer,
        "other": AnotherConsumer,
    }

Group

会话和用户

如上面所提到的,你可以通过设置 consumer 类的 channel_session 或者 channel_session_user 属性来设置用户会话。也可以设置 http_user 使用 Django 的 Session 和 User。之后便可以获取 message 对象的 channel_session 和 user 属性了。

对于函数 consumer,则可以使用 channels.auth.channel_session_user 等装饰器达到相同效果:

from channels.routing import route
from channels import Group
from channels.auth import channel_session_user, channel_session_user_from_http

@channel_session_user_from_http
def connect(message):
    pass

@channel_session_user
def disconnect(message):
    pass

channel_routing = [
    route('websocket.connect', connect),
    route('websocket.disconnect', disconnect),
]

backend

backend 是为 Django Channels 提供 channel 异步通信的后端,推荐使用 Redis 作为 backend。

根据 backend 的不同,channels 的行为可能会有所不同,比如 asgi_ipc.IPCChannelLayer 作为 backend 部署起来更简单,但是并不支持网络间通信。asgi_redis.RedisChannelLayer 虽然支持网络间通信,但是需要额外的 Redis 服务器支持。

Django Channels 支持 Redis、IPC 以及内存间通信,开发者可以根据应用场景和部署环境灵活选择 backend。

部署

设置 backend

需要在 Django 的 settings 里定义 CHANNEL_LAYERS

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "asgi_redis.RedisChannelLayer",      # 使用 asgi_redis 作为 backend
        "ROUTING": "my_project.routing.channel_routing",   # 指定路由文件
        "CONFIG": {
            "hosts": [("localhost", 6379)],             # 设置 Redis 的地址和端口
        },
    },
}

运行 worker 服务器

前面也提到了,Django Channels 将服务器解耦为协议服务器和 worker 服务器,因此也推荐单独部署 worker 服务器:python manage.py runworker

如果有需要,你甚至可以将不同的 channel 分别部署,Django Channels 支持 --only-channels 和 --exclude-channels用于过滤:

python manage.py runworker --only-channels=http.* --only-channels=websocket.*
python manage.py runworker --exclude-channels=thumbnail

运行接口服务器

由于 Django Channels 实现的是 ASGI 协议而不是 WSGI,因此你需要使用 ASGI 服务器来运行 channels 应用,例如 Daphne。使用 Daphne 还有一个好处就是,它会自动区分 HTTP 请求和 WebSocket 请求,因此并不需要分别启动两个服务器。

和 WSGI 应用部署类似,部署 ASGI 应用也需要首先指定 ASGI 应用本身,我们可以仿照 Django wsgi.py 的写法创建一个这样的 asgi.py 文件:

# coding: utf-8

import os
from channels.asgi import get_channel_layer

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_project.settings")

channel_layer = get_channel_layer()

然后运行 Daphne:daphne my_project.asgi:channel_layer

更新代码

更新代码后需要重启服务器,只要新代码兼容旧代码的会话。默认情况下,重启服务器意味着向服务器发送 SIGTERM 信号,服务器会在运行中的 consumer 执行完成以后重启并加载新代码。

同时运行 ASGI 和 WSGI

对于较大的项目,一个 ASGI 服务器 + 少许 worker 进程可能并不够用,这时推荐将 ASGI 和 WSGI 分离部署,更容易横向扩展。

 

分享到:
评论

相关推荐

    django channels实战(websocket底层原理和案例)

    在本文中,我们将深入探讨Django Channels的实战应用,以及WebSocket的底层原理和实际案例。Django Channels是Django框架的一个扩展,它允许我们处理非HTTP协议的通信,如WebSocket,从而实现了实时双向通信。理解...

    django-channels-webrtc-源码.rar

    《Django Channels与WebRTC深度解析》 Django Channels与WebRTC...本篇文章主要介绍了Django Channels与WebRTC的基本概念、工作原理以及它们的结合方式。希望对读者理解这两项技术及其在现代Web开发中的应用有所帮助。

    django_channels_websocket_example

    通过这个项目,你可以了解到Django Channels的工作原理,以及如何在Python Web应用中实现实时交互功能,这对于构建聊天应用、实时通知系统或其他需要即时反馈的应用场景非常有用。理解并实践这个示例,将有助于提升...

    Django+Channels开发的web端即时通讯.zip

    在本文中,我们将深入探讨如何使用Django框架与Channels库构建一个实时的...通过理解Django的MVC模式、Channels的工作原理以及WebSocket协议,你可以轻松创建一个实时、交互性强的Web应用,满足现代互联网用户的期望。

    基于python实时在线聊天博客问答系统(django+nuxt-vue+channels) .zip

    理解WebSocket的工作原理和如何在Django Channels中实现它至关重要。 9. UI/UX设计:Nuxt.js结合Vue.js的强大功能,可以创建具有吸引力的用户界面。理解基本的CSS和前端设计原则将有助于提高用户体验。 10. 部署和...

    python加django加websocket实现即时通讯

    在IT行业中,实时通信已经成为许多应用程序的核心需求,无论是在线聊天、游戏、股票交易还是协作工具。...开发者只需要理解WebSocket的基本原理,熟悉Django框架,就可以开始创建自己的实时Web应用。

    Django Channel实时推送与聊天的示例代码

    Django Channel是一个强大的工具,它扩展了Django框架的功能,使其能够处理不仅仅是...要深入了解Django Channels及其工作原理,建议查阅官方文档:https://channels.readthedocs.io/,那里有更详细的技术细节和教程。

    PyPI 官网下载 | channels_binding-1.4.21-py3-none-any.whl

    为了充分利用`channels_binding`库,开发者需要了解基本的WebSocket编程和Django Channels的工作原理。同时,阅读库的官方文档和示例代码可以帮助快速上手。在编写代码时,要注意正确设置通道层(Channel Layer),...

    轻量级flash服务器开发框架:Django

    同时,Django拥有丰富的第三方库,如Django Channels,可用于处理WebSocket协议,以支持与Flash的实时通信。 总结,"轻量级Flash服务器开发框架:Django"是一个关于利用Python的Django框架构建能与Flash组件交互的...

    real-Time-Chat-Django-channels

    本文将深入探讨如何使用Django Channels构建一个实时聊天应用。Django Channels是Django框架的一个扩展,它允许我们处理非HTTP协议的通信,如WebSocket,从而实现实时交互的功能,例如聊天室、实时通知等。在Python...

    Django Web

    此外,还可以了解到Django的最佳实践,以及如何利用Django的众多扩展来增强功能,如Django Rest Framework用于API开发,Django Channels支持WebSocket通信等。学习Django不仅可以提升Python Web开发技能,也为深入...

    Python异步编程|ASGI 与 Django(附源码)

    从Django 3.0版本开始,Django可以通过配置文件选择使用ASGI服务器运行,例如,使用Django的 Channels库,可以创建处理WebSocket和其他长连接的异步应用。 在实际应用中,我们可能需要修改Django的`settings.py`...

    Django开发宝典

    除了核心功能,Django还有丰富的第三方库和插件,如Django REST framework用于构建RESTful API,Django Channels支持WebSocket通信等。这些扩展使得Django在现代Web开发中的应用更加广泛。 总之,《Django开发宝典...

    Django是一个开放源代码的Web应用框架

    接下来,我们将深入探讨Django的主要特点、工作原理以及如何使用它来构建Web应用。 1. MVC(模型-视图-控制器)架构: Django遵循MVC模式,但稍有不同,它将“视图”(View)与“模板”(Template)分开,形成了...

    django_channels_tutorial:练习教程

    【django_channels_tutorial:...通过实践,你将熟悉Channels的工作原理和它如何改变Django处理请求的方式。同时,你也会了解到如何在Django项目中整合WebSocket和其他异步技术,从而为你的Web应用带来实时交互的体验。

    Django websocket原理及功能实现代码

    在Django框架下实现WebSocket功能,有两种常见方法:channels和dwebsocket。channels依赖于redis和twisted等组件,设置相对复杂,而dwebsocket则提供了一个更为简洁的解决方案。要使用dwebsocket,首先需要通过pip3 ...

    dj_websocket.zip

    在IT行业中,Websocket是一种在客户端和服务器之间建立持久连接的协议,允许双方实时、双向地交换数据。...开发者可以通过这个项目深入理解Django Channels的工作原理,并进一步提升其在实时应用开发中的技能。

    booktime:继F. Marani的出色著作“ Practical Django 2 and Channels 2”(实用的Django 2和Channels 2)之后

    7. Channels 2基础:理解ASGI和WebSockets的工作原理,配置Channels,创建消费者来处理WebSocket连接。 8. 实时应用:构建聊天应用或其他需要实时更新的场景,如股票报价或游戏状态。 9. 部署和优化:学习如何将...

Global site tag (gtag.js) - Google Analytics