对于websocket的浅浅理解

测试环境以及版本

说明:其实django3.0已经自带websocket的处理器了,我是用channels实现的。感兴趣的可以直接使用asgi实现。django3以上项目路径下会自带这个asgi.py文件。

Django==3.1.5
python==3.7
channels==3.0.3
channels-redis==3.2.0

项目结构树

django项目中的settings文件

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "channels",  # 放在最上面

]

同级新建routings.py文件

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter

import 你的app.routing as device

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter(
            device.websocket_urlpatterns
        )
    ),
})

app下新建routings.py文件

from django.conf.urls import url
from django.urls import path
from app.consumers import DeviceConsumer

websocket_urlpatterns = [
    url(r'ws/device/?$', DeviceConsumer.as_asgi()),
]

app下新建consumers.py文件

import json

from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer     # 异步,实现更好的性能

from cies_device.models import Device
from codex.exceptions import DBDataCRUDError

web_clients = {}


class DeviceConsumer(AsyncWebsocketConsumer):
    actuator_status = {}

    async def connect(self):
        # connect方法在连接建立时触发
        self.room_group_name = 'chat_test'
        for i, j in self.scope["headers"]:
            if i.decode() == "clientlite":
                k = i.decode()
                v = j.decode().split(":")[-1]
                self.room_group_name = v
                if web_clients.get(k, []):
                    if v not in web_clients[k]:
                        web_clients[k].append(v)
                else:
                    web_clients[k] = [v]
        print(web_clients)
        # 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):
        # disconnect在连接关闭时触发
        # Leave room group

        # 断开连接后将注册的channel删除
        if "clientlite" in list(web_clients.keys()) and self.room_group_name != "chat_test":
            web_clients["clientlite"].remove(self.room_group_name)

        # Send message to room group
        await self.channel_layer.group_send(
            "chat_test",
            {
                'type': 'device_message',
                'message': list(self.actuator_status.values())[0] if self.actuator_status else {}
            }
        )

        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    @database_sync_to_async
    def save_to_db(self, data):
        # 创建数据
        sub_uids = []
        try:
            f = Device._meta.many_to_many[0].related_model
            sub_devices = data.get("devices", [])
            for i in sub_devices:
                uid = i.get("uid", "")
                f.objects.update_or_create(i, **{"uid": uid})
                sub_uids.append(uid)
            data.pop("devices")
            uid = data.get("uid", "")
            ip = data.get("ip", "")
            res = Device.objects.update_or_create(data, **{"uid": uid})
            # 更新状态
            if ip in self.actuator_status.keys():
                if self.actuator_status[ip]["actuator_status"] != data.get("actuator_status", ""):
                    self.actuator_status[ip]["actuator_status"] = data.get("actuator_status", "")
            else:
                self.actuator_status[ip] = {"uid": uid, "actuator_status": data.get("actuator_status", "")}
            if sub_uids:
                fn = Device._meta.many_to_many[0].name
                fl_obj = f.objects.filter(uid__in=sub_uids)
                eval("res[0].{}".format(fn)).add(*fl_obj)
        except Exception as e:
            print(e)
            raise DBDataCRUDError("数据入库失败 {}".format(e))
        return "数据入库成功"

    # Receive message from WebSocket

    async def receive(self, text_data):
        # receive方法会在收到消息后触发
        text_data_json = json.loads(text_data)
        if self.room_group_name != "chat_test":
            h5_msg = text_data_json.pop("actuator")
            if h5_msg == "Info":
                await self.save_to_db(text_data_json)
            else:
                await self.channel_layer.group_send(
                    "chat_test",
                    {
                        'type': 'device_message',
                        'message': text_data
                    }
                )

    # Receive message from room group
    async def device_message(self, event):
        message = event['message']
        print("收到数据{} 并发送".format(message))
        # Send message to WebSocket 【最后在这里发送返回前端页面】
        await self.send(text_data=json.dumps(message))


测试websocket需注意的点

import time
from django.conf import settings#  这必须有
from cies import settings as s#  这必须有
settings.configure(s)#  这必须有
import os#  这必须有
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cies.settings")#  这必须有


from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
#
# # Create your tests here.
#
#
def send_group_msg(channel_name, message):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)("{}".format(channel_name), {
        "type": "device_message",
        "message": message,
    })


if __name__ == '__main__':
    n = 1
    #
    while n<10000:
        d = "dadda"+str(n)
        send_group_msg("chat_test", d)
        n += 1
        time.sleep(0.5)

然后就可以随处调用了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值