Django系列之Channels
1. Channels 介绍
Django 中的 HTTP 请求是建立在请求和响应的简单概念之上的。浏览器发出请求,Django服务调用相应的视图函数,并返回响应内容给浏览器渲染。但是没有办法做到 服务器主动推送消息给浏览器。
因此,WebSocket 就应运而生了。WebSocket 是一种基于 HTTP 基础上进行全双工通讯的协议。WebSocket允许服务端主动向客户端推送数据。在WebSocket协议中,浏览器和服务器只需要完成一次握手就可以创建持久性的连接,并在浏览器和服务器之间进行双向的数据传输。
Django Channels 实现了 WebSocket 能力。Channels 允许 Django 以非常类似于传统 HTTP 的方式支持WebSockets。Channels 也允许在运行 Django 的服务器上运行后台任务,HTTP 请求表现以前一样,但也支持通过 Channels 进行路由。
Django channels安装:pip install channels
2. channels 单人聊天
配置文件 settings.py:
INSTALLED_APPS = [...'app01.apps.App01Config','channels'
]
ASGI_APPLICATION = 'djangoProject.asgi.application'
主路由文件 urls.py:
from app01 import views as vw1urlpatterns = [path('admin/', admin.site.urls),path("chatone", vw1.chat)
]
主业务视图文件 app01/views.py:
from django.shortcuts import renderdef chat(request):return render(request, "chatting.html")
主业务html文件 chatting.html:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.message {height: 300px;border: 1px solid #dddddd;width: 100%;}</style>
</head>
<body><div class="message" id="message"></div><div><input type="text" placeholder="请输入聊天内容:" id="txt"><input type="button" value="点击发送" onclick="sendMessage()"><input type="button" value="关闭连接" onclick="closeConn()"></div><script>// 实例化websocket对象,并客户端主动以websocket方式连接服务端wbsocket = new WebSocket("ws://127.0.0.1:8080/room/123/");// 创建好websocket连接成功后自动触发(服务端执行self.accept()后)wbsocket.onopen = function (event) {var tag = document.createElement("div");tag.innerText = '[连接成功!]';document.getElementById("message").appendChild(tag);};// 创建连接失败后自动触发wbsocket.onerror = function (event) {var tag = document.createElement("div");tag.innerText = '[连接失败!]';document.getElementById("message").appendChild(tag);};// 当websocket接收到服务器发来的消息时会自动触发wbsocket.onmessage = function (event) {var tag = document.createElement("div");tag.innerText = event.data;document.getElementById("message").appendChild(tag);};// 当服务端主动断开客户端时自动触发(服务端执行self.close()后)wbsocket.onclose = function (event) {var tag = document.createElement("div");tag.innerText = '[连接已断开!]';document.getElementById("message").appendChild(tag);};// 页面上客户端点击向服务端"关闭连接"时触发function closeConn() {wbsocket.close(); // 客户端主动断开连接,服务端会执行 websocket_disconnect()var tag = document.createElement("div");tag.innerText = '[连接已断开啦!]';document.getElementById("message").appendChild(tag);}// 页面上客户端点击向服务端"发送消息"时触发function sendMessage() {var info = document.getElementById("txt");wbsocket.send(info.value); // 客户端给服务端发数据}</script></body>
</html>
websocket路由文件 routings.py:
from django.urls import re_path
from app01 import consumers as consm1websocket_urlpatterns = [re_path(r'room/', consm1.ChatConsumer.as_asgi())
]
处理websocket业务文件 app01/consumers.py:
from channels.exceptions import StopConsumer
from channels.generic.websocket import WebsocketConsumerclass ChatConsumer(WebsocketConsumer):def websocket_connect(self, message):"""客户端向服务端发送websocket连接的请求时自动触发。"""print("1 > 客户端和服务端开始建立连接")self.accept()def websocket_receive(self, message):"""客户端基于websocket向服务端发送数据时,自动触发接收消息。"""print(f"2 > 服务端接收客户端的消息, message is {message}")recv_data = message["text"]if recv_data == "exit": # 服务端主动关闭websocket连接时,前端会执行对应的 oncloseself.close()# raise StopConsumer() # raise主动抛异常后,websocket_disconnect 就不在执行了,多用于`只处理服务端向客户端断开`的场景returnsend_data = f"服务端主动推送消息:{recv_data}"self.send(text_data=send_data)def websocket_disconnect(self, message):"""客户端与服务端断开websocket连接时自动触发(不管是客户端向服务端断开还是服务端向客户端断开都会执行)"""print("3 > 客户端和服务端断开连接")self.close()raise StopConsumer()
3. channel_layer 群组聊天
对于大多数情况来说,发送到单人的 channel 并没有用,更多的情况下希望可以以广播的方式将message 一次性发送给多个 channel 或者 consumer,这不仅适用于想在向房间内的每个人发送消息,还适用于发送给连接了多个浏览器/标签/设备的用户。
channel_layer 是一种通信系统。它允许多个消费者实例相互交谈,借助 channel_layer 可以很方便的实现群聊功能,我们无需手动管理 websocket 连接。channel 官方推荐的是配置channel_redis,它是一个使用Redis作为传输的Django维护层。安装:pip install channels_redis。
channel_layer 属于纯粹的异步接口,如果想要改成同步代码调用,需要使用async_to_sync做转换:
from asgiref.sync import async_to_sync。
配置文件 settings.py:
ASGI_APPLICATION = 'djangoProject.asgi.application'# 开发环境使用
CHANNEL_LAYERS = {"default": {"BACKEND": "channels.layers.InMemoryChannelLayer"}
}# 真实生产环境上使用
CHANNEL_LAYERS = {"default": {"BACKEND": "channels_redis.core.RedisChannelLayer","CONFIG": {"hosts": ["redis://127.0.0.1:6379/1", ], # 无密码连接redis# "hosts": ["redis://:password@127.0.0.1:6379/1", ], # 有密码连接redis# "symmetric_encryption_keys": [SECRET_KEY]}}
}
主路由文件 urls.py:
from django.contrib import admin
from django.urls import path
from app01 import views as vw1
from app02 import views as vw2urlpatterns = [path('admin/', admin.site.urls),path("chatone", vw1.chat),path("chatgroup", vw2.groupchat) # 群聊
]
主业务视图 app02/views.py:
from django.shortcuts import renderdef groupchat(request):groupid = request.GET.get("groupID") # 获取群组IDreturn render(request, "groupchatting.html", {"group_num": groupid})
主业务html文件 chatting.html: js在实例化websocket对象时需要改动。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.message {height: 300px;border: 1px solid #dddddd;width: 100%;}</style>
</head>
<body><div> 群组内聊天[ 群ID: {{ group_num }} ] </div><div class="message" id="message"></div><div><input type="text" placeholder="请输入群聊内容:" id="txt"><input type="button" value="点击发送" onclick="sendMessage()"><input type="button" value="关闭连接" onclick="closeConn()"></div><script>// 实例化websocket对象,并客户端主动以websocket方式连接服务端wbsocket = new WebSocket("ws://127.0.0.1:8080/group/{{ group_num }}/");// 创建好websocket连接成功后自动触发(服务端执行self.accept()后)wbsocket.onopen = function (event) {var tag = document.createElement("div");tag.innerText = '[连接成功!]';document.getElementById("message").appendChild(tag);};// 创建连接失败后自动触发wbsocket.onerror = function (event) {var tag = document.createElement("div");tag.innerText = '[连接失败!]';document.getElementById("message").appendChild(tag);};// 当websocket接收到服务器发来的消息时会自动触发wbsocket.onmessage = function (event) {var tag = document.createElement("div");tag.innerText = event.data;document.getElementById("message").appendChild(tag);};// 页面上客户端点击向服务端"关闭连接"时触发function closeConn() {wbsocket.close(); // 客户端主动断开连接,服务端会执行 websocket_disconnect()var tag = document.createElement("div");tag.innerText = '[连接已断开!]';document.getElementById("message").appendChild(tag);}// 页面上客户端点击向服务端"发送消息"时触发function sendMessage() {var info = document.getElementById("txt");wbsocket.send(info.value); // 客户端给服务端发数据}</script></body>
</html>
websocket 路由文件 routings.py:
from django.urls import re_path
from app01 import consumers as consm1
from app02 import consumers as consm2websocket_urlpatterns = [re_path(r'room/', consm1.ChatConsumer.as_asgi()),re_path(r"group/(?P<groupID>\w+)/$", consm2.GroupChatConsumer.as_asgi()) # 群聊
]
websocket 群聊业务文件 consumers.py:
注意:从路由url中获取参数时,要使用 self.scope["url_route"]["kwargs"].get("groupID"),这里的 groupID 必须和routings中的路由分组名 re_path(r"group/(?P<groupID>\w+)/$" 保持一致!!!
from asgiref.sync import async_to_sync
from channels.exceptions import StopConsumer
from channels.generic.websocket import WebsocketConsumerclass GroupChatConsumer(WebsocketConsumer):group_id = Nonedef websocket_connect(self, message):# 接受客户端连接self.accept()print(">>> 客户端和服务端已成功建立连接 <<<")# 从url获取群组id,这个groupID必须和routings里的路由分组名保持一致self.group_id = self.scope["url_route"]["kwargs"].get("groupID")# 将当前的连接加入到名为self.group_id的组中async_to_sync(self.channel_layer.group_add)(self.group_id, self.channel_name)def websocket_receive(self, message):print(f"current self is {self}, id is {id(self)}, groupID is {self.group_id}")# 组内所有的客户端,执行type对应的函数,可以在此函数中自定义任意功能async_to_sync(self.channel_layer.group_send)(self.group_id, {"type": "send_msg", "message": message})def send_msg(self, event):input_msg = event["message"].get("text")send_msg = f"组内主动推送消息:{input_msg}"self.send(text_data=send_msg)def websocket_disconnect(self, message):# self.channel_name从组self.group_id中删除并断开连接async_to_sync(self.channel_layer.group_discard)(self.group_id, self.channel_name)print(">>> 客户端和服务端已断开连接 <<<")raise StopConsumer()
相关文章:
Django系列之Channels
1. Channels 介绍 Django 中的 HTTP 请求是建立在请求和响应的简单概念之上的。浏览器发出请求,Django服务调用相应的视图函数,并返回响应内容给浏览器渲染。但是没有办法做到 服务器主动推送消息给浏览器。 因此,WebSocket 就应运而生了。…...
HTTP——五、与HTTP协作的Web服务器
HTTP 一、用单台虚拟主机实现多个域名二、通信数据转发程序 :代理、网关、隧道1、代理2、网关3、隧道 三、保存资源的缓存1、缓存的有效期限2、客户端的缓存 一台 Web 服务器可搭建多个独立域名的 Web 网站,也可作为通信路径上的中转服务器提升传输效率。…...
pyspark笔记 Timestamp 类型的比较
最近写pyspark遇到的一个小问题。 假设我们有一个pyspark DataFrame叫做dart 首先将dart里面timestamp这一列转化成Timestamp类型 dartdart.withColumn(timestamp,col(timestamp).cast(TimestampType()))查看timestamp的前5个元素 dart.select(timestamp).show(5,truncateFal…...
SpringBoot 集成 Redis
本地Java连接Redis常见问题: bind配置请注释掉保护模式设置为noLinux系统的防火墙设置redis服务器的IP地址和密码是否正确忘记写访问redis的服务端口号和auth密码 集成Jedis jedis是什么 Jedis Client是Redis官网推荐的一个面向java客户端,库文件实现…...
黑客学习笔记(网络安全)
一、首先,什么是黑客? 黑客泛指IT技术主攻渗透窃取攻击技术的电脑高手,现阶段黑客所需要掌握的远远不止这些。 以前是完全涉及黑灰产业的反派角色,现在大体指精通各种网络技术的程序人员 二、为什么要学习黑客技术?…...
[openCV]基于拟合中线的智能车巡线方案V1
import cv2 as cv import os import numpy as np# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir:文件夹根目录输入 ext: 扩展名返回: 文件路径列表"""newDir d…...
MyBatis-Plus 和达梦数据库实现高效数据持久化
一、添加依赖 首先,我们需要在项目的 pom.xml 文件中添加 MyBatis-Plus 和达梦数据库的依赖: <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifac…...
已注销【888】
元神密码 - 飞书云文档 (feishu.cn)...
Ceph错误汇总
title: “Ceph错误汇总” date: “2020-05-14” categories: - “技术” tags: - “Ceph” - “错误汇总” toc: false original: true draft: true Ceph错误汇总 1、执行ceph-deploy报错 1.1、错误信息 ➜ ceph-deploy Traceback (most recent call last):File "/us…...
DataTable过滤某些数据
要过滤DataTable中的某些数据,可以使用以下方法: 使用Select方法:可以使用DataTable的Select方法来筛选满足指定条件的数据行。该方法接受一个字符串参数作为过滤条件,返回一个符合条件的数据行数组。 DataTable filteredTable …...
JAVASE---继承和多态
继承 比如,狗和猫,它们都是一个动物,有共同的特征,我们就可以把这种特征抽取出来。 像这样把相同的可以重新放到一个类里面,进行调用,这就是继承。 概念 继承(inheritance)机制:是面向对象程…...
Centos7升级gcc、g++版本(转载)
Centos7默认的 gcc版本是 4.8.5 默认使用yum install gcc安装出来的gcc版本也是是4.8.5。 1.首先查看自己的 gcc 版本 gcc -v g -v如果出现:bash: g: 未找到命令... 则安装g:遇到暂停时,输入y继续安装 yum install gcc-c然后输入…...
第一章:继承
系列文章目录 文章目录 系列文章目录前言继承的概念及定义继承的概念继承定义定义格式继承关系和访问限定符继承基类成员访问方式的变化 基类和派生类对象赋值转换(公有继承)继承中的作用域派生类的默认成员函数继承与友元继承与静态成员不能被继承的类复…...
git面试题
文章目录 git经常用哪些指令git出现代码冲突怎么解决你们团队是怎么管理git分支的如何实现Git的免密操作 git经常用哪些指令 产生代码库 新建一个git代码库 git init下载远程项目和它的整个代码历史 git clone 远程仓库地址配置 显示配置 git config --list [--global]编辑配置…...
Github Copilot在JetBrains软件中登录Github失败的解决方案
背景 我在成功通过了Github Copilot的学生认证之后,在VS Code和PyCharm中安装了Github Copilot插件,但在PyCharm中插件出现了问题,在登录Github时会一直Retrieving Github Device Code,最终登录失败。 我尝试了网上修改DNS&…...
使用 github 同步谷歌浏览器书签
想必使用谷歌浏览器Chrome的用户一定非常头疼的一件事就是:账户不能登录,书签收藏夹不能同步,换一台电脑书签收藏夹没有了! 下面教大家一招亲测有效适用的方法解决书签同步问题,在任何电脑都可以同步了 1、去下载谷歌…...
Eclipse进行debug
目录 基本步骤三种执行方式 -- 键盘快捷键variables面板移除debug过的项目通过eclipse调用具有软件界面的项目进行debug各个variable颜色具有的意义 基本步骤 点击eclipse右上角debug按钮 调出debug面板 点击小蜘蛛图标(不是点绿色三角的Run) 此时会进…...
13-5_Qt 5.9 C++开发指南_基于信号量的线程同步_Semaphore
文章目录 1. 信号量的原理2. 双缓冲区数据采集和读取线程类设计3. QThreadDAQ和QThreadShow 的使用4. 源码4.1 可视化UI设计框架4.2 qmythread.h4.3 qmythread.cpp4.4 dialog.h4.5 dialog.cpp 1. 信号量的原理 信号量(Semaphore)是另一种限制对共享资源进行访问的线程同步机制…...
golang使用泛型实现mapreduce操作
1.使用面向对象的方式写 package streamimport ("fmt""log""reflect""sort""strconv""strings" )type Stream[T any] struct {data []TkeyBy stringsortByNum stringsortByStr []string }func FromElem…...
2023华数杯数学建模C题思路分析 - 母亲身心健康对婴儿成长的影响
# 1 赛题 C 题 母亲身心健康对婴儿成长的影响 母亲是婴儿生命中最重要的人之一,她不仅为婴儿提供营养物质和身体保护, 还为婴儿提供情感支持和安全感。母亲心理健康状态的不良状况,如抑郁、焦虑、 压力等,可能会对婴儿的认知、情…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
