python异步编程-channels使用,创建websocket服务

2024-08-22 04:52

本文主要是介绍python异步编程-channels使用,创建websocket服务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • channels介绍
  • 准备工作
    • 创建python虚拟环境
    • 安装channels
    • 安装django
    • 安装daphne
    • 创建django项目
    • 创建chat应用
  • 配置instance项目
  • 简单聊天室页面
    • 在chat应用中创建模板
      • base.html
      • room.html
    • 添加视图
    • 添加路由
      • 添加urls.py
      • 项目路由添加chat转发路由
      • 启动同步服务器
  • 搭建websocket服务
    • 创建channels路由
      • 新增协议使用者
      • 新增websocket路由
      • 创建asgi的application
      • 配置asgi应用
      • 修改项目的asgi文件
  • 启动通道层
    • settings中配置
  • daphne部署
  • 验证
  • 总结

channels介绍

channels是一个用来构建实时web应用的强大工具,比如聊天室、在线游戏,多人协作、实时通知等。今天简单介绍一下,用channels搭建一个简易的websocket服务。

准备工作

创建python虚拟环境

mkdir instance
cd install
python -m venv venv# 激活虚拟环境
source venv/bin/activate # linux
./venv/bin/activate.bat # window

安装channels

pip install channels

安装django

pip install django

安装daphne

这个稍后会用到,用来启动异步服务器使用

pip install daphne

创建django项目

django-admin startproject instance 

创建chat应用

django-admin startapp chat

配置instance项目

在instance/instance目录下,修改settings.py文件

建议最好用pycharm打开

# instance/instance/settings.py ...
INSTALLED_APPS = ['daphne', # 新增'django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','django.contrib.sites','django.contrib.sitemaps','chat', # 新增'channels', # 新增
]
...
TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [BASE_DIR / 'templates'],'APP_DIRS': True,'OPTIONS': { # 此处options可以不配置,与我们的功能无关'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},
]
...

简单聊天室页面

在chat应用中创建模板

需要创建两个模板文件,其中room.html 继承base.html

base.html

主要定义了页面的基本结构,具体内容在子模板中填充
instance/chat/template/chat/base.html

{% load static %}
<!DOCTYPE html>
<html>
<head><meta charset=""utf-8><title>{% block title %}Education{% endblock %}</title><link href="{% static "css/base.css" %}" rel="stylesheet">
</head>
<body>
<div id="header"><a href="/" class="logo">Education</a><ul class="menu">{% if request.user.is_authenticated %}<li><a href="{% url "logout" %}">Sign out</a> </li>{% else %}<li><a href="{% url "login" %}">Sign in</a> </li>{% endif %}</ul>
</div>
<div id="content">{% block content %}{% endblock %}
</div><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>$(document).ready(function(){{% block domready %}{% endblock %}});
</script>
</body>
</html>

room.html

主要实现了一个输入框一个发送按钮,以及可以展示消息的div元素,页面简陋,能看即可

除了页面结构,还加了websocket链接的js代码

{% extends "chat/base.html" %}{% block title %} Chat room for "{{ course.title }}" {% endblock %}{% block content %}
<div id="chat"></div>
<div id="chat-input"><input id="chat-message-input" type="text"><input id="chat-message-submit" type="submit" value="Send">
</div>
{% endblock %}{% block domready %}var url = 'ws://' + window.location.host + '/ws/chat/room/' + '{{ course }}' + '/';console.log(url);var chatSocket = new WebSocket(url);console.log(chatSocket);chatSocket.onmessage = function(e) {var data = JSON.parse(e.data);var message = data.message;var $chat = $('#chat');$chat.append('<div class="message">' + message + '</div>');$chat.scrollTop($chat[0].scrollHeight);};chatSocket.onclose = function (e) {console.error('chat socket close unexpectedly');};var $input = $('#chat-message-input');var $submit = $('#chat-message-submit');$submit.click(function(){var message = $input.val();if(message) {chatSocket.send(JSON.stringify({'message': message}));$input.val('');$input.focus();}});$input.focus();$input.keyup(function (e){if(e.which === 13) {$submit.click();}});
{% endblock %}

添加视图

编辑chat目录下views.py

from django.shortcuts import renderdef course_chat_room(request, course_id):return render(request, 'chat/room.html', {'course': 1})

添加路由

添加urls.py

chat目录下新增urls.py

from django.urls import pathfrom chat import viewsapp_name = 'chat'urlpatterns = [path('room/<int:course_id>/', views.course_chat_room, name='course_chat_room'),
]

项目路由添加chat转发路由

编辑instance/instance/urls.py

urlpatterns = [path('admin/', admin.site.urls),path('chat/', include('chat.urls', namespace='chat')), # 新增...,
]

启动同步服务器

到这一步就可以启动wsgi服务器,查看页面

python manage.py runserver

启动后,在浏览器中打开网站http://127.0.0.1:8000/chat/room/1/ 可以看到页面
我这里有样式设置,所以可能你们电脑上看到的样式不一样,但是基本结构时一样的
在这里插入图片描述

搭建websocket服务

我们前面已经将channels 应用添加到settings中的INSTALLED_APPS中

所以可以直接配置channels

创建channels路由

新增协议使用者

channels中一个很重要的概念就是消费者,也叫使用者,本质上就是协议请求接收之后的处理者

chat目录下新建consumers.py

这里使用了异步实现,将注释掉的代码恢复,就是同步代码

import jsonfrom channels.generic.websocket import WebsocketConsumer, AsyncWebsocketConsumer
from asgiref.sync import async_to_sync
from django.utils import timezone# class ChatConsumer(WebsocketConsumer):
class ChatConsumer(AsyncWebsocketConsumer):async def connect(self):self.user = self.scope['user']self.id = self.scope['url_route']['kwargs']['course_id']self.room_group_name = 'chat_%s' % self.id# async_to_sync(self.channel_layer.group_add)(self.room_group_name, self.channel_name)await self.channel_layer.group_add(self.room_group_name, self.channel_name)# accept connectionawait self.accept()async def disconnect(self, code):# async_to_sync(self.channel_layer.group_dicard)(self.room_group_name, self.channel_name)await self.channel_layer.group_dicard(self.room_group_name, self.channel_name)# receive message from WebSocketasync def receive(self, text_data=None, bytes_data=None):text_data_json = json.loads(text_data)message = text_data_json["message"]# send message to WebSocket# self.send(text_data=json.dumps({'message': message}))now = timezone.now()# send message to room groupawait self.channel_layer.group_send(self.room_group_name, {"type": "chat_message","message": message,"user": self.user.username,"datetime": now.isoformat(),})async def chat_message(self, event):await self.send(text_data=json.dumps(event))

新增websocket路由

chat下新增routing.py

from django.urls import re_path
from chat import consumerswebsocket_urlpatterns = [re_path(r'ws/chat/room/(?P<course_id>\d+)/$', consumers.ChatConsumer.as_asgi()),
]

创建asgi的application

在instance/instance下新建routing.py

这里我们使用的ProtocolTypeRouter 协议路由,区分不同的协议使用不同的路由方式
http一定要配置,否则正常的http请求无法处理,会报错
其次就是新增了websocket协议
如此创建之后,才能应用websocket协议

import osfrom channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.core.asgi import get_asgi_applicationimport chat.routingos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'instance.settings')application = ProtocolTypeRouter({'http': get_asgi_application(),'websocket': AuthMiddlewareStack(URLRouter(chat.routing.websocket_urlpatterns))
})

配置asgi应用

instance/instance/settings.py中新增配置项

...
ASGI_APPLICATION = 'instance.routing.application'
...

修改项目的asgi文件

修改instance/instance/asgi.py

import os
import django
from django.core.asgi import get_asgi_application
from channels.routing import get_default_applicationos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'instance.settings')
django.setup()
# application = get_asgi_application()
application = get_default_application()

OK,走到这一步,就可以在聊天室内发送消息了,只不过我们为了模拟而已,所以没有两个用户,只是把发送过来的消息再转发回client端,并显示在页面上

你是不是用了python manage.py runserver 启动,发现没有任何变化,然后打开F12 发现websocket链接失败

别急,往下看

启动通道层

通道层类似于传话筒,能够实现不同应用之间的通信,也可以支持使用者实例之间的通信

一般常用的通道层后台是redis
这里我们为了演示,就直接本地内存作为通道层缓存

settings中配置

配置下面的项,则自动启动通道层
不配置或者保留为空,则不启动

CHANNEL_LAYERS = {"default": {"BACKEND": "channels.layers.InMemoryChannelLayer",}
}

daphne部署

如果你使用了python manage.py runserver 发现没有效果,可以尝试daphne部署

django项目的测试服务器,默认启动的都是wsgi程序,不支持异步处理

而websocket的应用一般都是异步(同步的话就没有了意义)

所以我们要使用能够部署异步服务器的工具

就是daphne

daphne 支持asgi应用,基于我们上面写好的代码和创建的项目结构,启动方式如下

daphne instance.asgi:application
# 或者
daphne instance.routing:application

此时应该就可以了!

验证

启动之后,可以浏览器中多打开几个页面,因为我们没有做鉴权,所以每个页面都会创建一个websocket链接,相当于多个client

在其中一个页面中发送消息,那么其他页面也会同步刷新

之后优化一下页面结构,那就是一个简易聊天室了
在这里插入图片描述
在这里插入图片描述

总结

channels是一个能够处理实时协议的强大工具,这个协议可以是http,websocket,也可以是其他的需要实时通讯的情况。

daphne命令可以启动验证,也可以直接使用在生产环境,是安全的

这篇关于python异步编程-channels使用,创建websocket服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1095298

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]