zoukankan      html  css  js  c++  java
  • Django--channels

    channels介绍
    channels是以django插件的形式存在,它不仅能处理http请求,还提供对websocket、MQTT等长连接支持。
    不仅如此,channels在保留了原生django的同步和易用的特性上还带来了异步处理方式(channels2.X版本),并且将django自带的认证系统以及session集成到模块中,扩展性非常强。
     
    安装
    pip3 install channels
    pip3 install channels-redis    #可选的,官方推荐如果使用redis作为channel layer
     
    开始使用
    一、配置settings.py
      笔者采用的redis作为channel layer(关于其介绍请移步至https://channels.readthedocs.io/en/latest/topics/channel_layers.html),它是实现消息推送的核心,在项目的settings.py中:
    注册channles app:
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'cmdb',
        'channels', #注册app
    ]

    配置channels layer:

    ASGI_APPLICATION = 'devops.routing.application'
    CHANNEL_LAYERS = {
        'default': {
            'BACKEND': 'channels_redis.core.RedisChannelLayer',
            'CONFIG': {
                "hosts": [('10.1.210.33', 6379)], #需修改
            },
        },
    }
    二、路由配置
    在项目settings文件同级目录中新增routing.py
    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里配置路由和对应的消费者,笔者这里是devops下的routing.py: 
    from django.conf.urls import url
    from . import consumers
    
    websocket_urlpatterns = [
        url(r'^ws/deploy/(?P<service_name>[^/]+)/$', consumers.DeployResult), #consumers.DeployResult 是该路由的消费者
    ]
     
    三、编写webscoket消息处理方法(消费者)
    首先说明,消费者是Channels代码的基本单元,当一个新的Socket进入的时候,Channels会根据路由表找到正确的消费者,以下代码中每个方法都可以看作一个消费者,他们消费不同的event,比如刚刚接受连接时候connect方法进行消费处理并接受连接,关闭websocket时候使用disconnect进行消费处理。
    deploy/consumers.py: 
    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
            # 收到连接时候处理,
            await self.channel_layer.group_add(
                self.chat_group_name,
                self.channel_name
            )
    
            await self.accept()
    
        async def disconnect(self, close_code):
            # 关闭channel时候处理
            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)
            # 发送消息到组
            await self.channel_layer.group_send(
                self.chat_group_name,
                {
                    'type': 'client.message',
                    'message': message
                }
            )
    
        # 处理客户端发来的消息
        async def client_message(self, event):
            message = event['message']
            print("发送消息。。。",message)
            # 发送消息到 WebSocket
            await self.send(text_data=json.dumps({
                'message': message
            }))
    以上代码部分说明:
    1.self.scope是单个连接传入的详细信息,其中包含了请求的session、以及django认证系统中的用户信息等;
    2.async...await 是python3.5之后的新异步特性,基于asyncio模块;
     
    四、发起webscoket请求
    利用js发起websocket请求
    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 = '
    ' + data['message'];
                    document.querySelector('#deploy-res').innerText += (message + '
    ');
                };
    }
    五、发送消息到channel
    无论是消息的推送或者消息的接受,都是经过channel layer进行传输,以下是发送消息示例,
    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})
     
    六、生产部署
    大多数django的应用部署方式都采用的是nginx+uwsgi进行部署,当django集成channels时候,由于uwsgi不能处理websocket请求,所以我们需要asgi服务器来处理websocket请求,官方推荐使用daphne。
     
     

  • 相关阅读:
    【转】JMeter学习(十六)JMeter函数学习
    【转】JMeter学习(十三)分布式部署
    【转】JMeter学习(十二)目录介绍
    【转】JMeter学习(十一)WebSerivice测试计划
    【转】JMeter学习参数化User Defined Variables与User Parameters
    JMeter学习(九)FTP测试计划
    【转】JMeter学习(八)JDBC测试计划-连接Oracle
    【转】JMeter学习(七)聚合报告之 90% Line 正确理解
    【转】JMeter学习(六)集合点
    springboot整合mybatisplus
  • 原文地址:https://www.cnblogs.com/absoluteli/p/13983840.html
Copyright © 2011-2022 走看看