• django websocket


    Django webSocket

    源代码:https://github.com/wztshine/django_websocket_demo

    参考自:

    https://www.cnblogs.com/wupeiqi/articles/9593858.html

    https://www.bilibili.com/video/BV1aM4y137Qu?p=10&spm_id_from=pageDriver

    配置

    • 安装
    pip install channels
    pip install django
    
    • 创建项目

    命令行输入:

    django-admin startproject ws_channel  # ws_channel 是项目名,会在当前路径下出现这样一个文件夹
    
    • 进入项目文件夹,修改 ws_channel/settings.py
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'channels',  # 这里修改了:添加 channels 模块
    ]
    
    # ws_channel 是当前 settings.py 文件所在的文件夹,即 python 的包名;asgi 是包下的 asgi.py 模块,它支持异步和 websockt
    ASGI_APPLICATION = "ws_channel.asgi.application"
    

    Django 3.0 以上版本,会自动生成一个 asgi.py 文件, 和 settings.py 同级目录。

    • 修改 ws_channel/asgi.py(如果你用的django不是3.0以上版本,自己手动创建这个文件)
    """
    ASGI config for ws_channel project.
    
    It exposes the ASGI callable as a module-level variable named ``application``.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
    """
    
    import os
    
    from django.core.asgi import get_asgi_application
    from channels.routing import ProtocolTypeRouter, URLRouter
    
    from . import routing
    
    
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ws_channel.settings')
    
    # application = get_asgi_application()
    application = ProtocolTypeRouter({
        "http": get_asgi_application(),  # 自动处理 http 请求
        'websocket': URLRouter(routing.websocket_urlPatterns),  # 使用自定义的路由系统,来处理 websocket 连接
    })
    
    • 创建编写 ws_channel/routing.py (settings.py 同级目录下)
    from channels.routing import ProtocolTypeRouter, URLRouter
    from django.urls import re_path
    
    from app01 import consumers
    
    
    websocket_urlPatterns = [
        re_path(r"", consumers.ChatConsumer.as_asgi()),  # 匹配路由
    ]
    
    • 新建一个 app01 的应用,并在应用下编写 consumers.py
    1. 在你当前的工程目录下,运行cmd命令:
    django-admin startapp app01  # 创建一个叫 app01 的应用
    
    1. 编写 app01/consumers.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from channels.generic.websocket import WebsocketConsumer
    from channels.exceptions import StopConsumer
    
    
    class ChatConsumer(WebsocketConsumer):
    
        def websocket_connect(self, message):
            """这个函数是用来建立连接的。当客户端发起连接时,服务端会自动触发这个函数"""
            print('开始握手')
            self.accept()  # 接受连接
    
        def websocket_receive(self, message):
            """客户端发来消息时,服务端自动调用这个方法接受消息"""
            print('接收到消息', message)
            self.send(text_data='收到了')  # send 方法可以发送消息
    
        def websocket_disconnect(self, message):
            """
            服务端主动调用 self.close() 时,或者客户端调用 close() 方法来关闭连接时,服务端都会自动运行这个方法,关闭连接
            :param message:
            :return:
            """
            print('客户端断开连接了')
            raise StopConsumer()
    
    

    简单的聊天室

    在上面的前提下,在 ws_channel/settings.py 中注册 app01

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config',  # 注册 app01 
        'channels',
    ]
    

    ws_channel/urls.py 中添加路由:

    from django.contrib import admin
    from django.urls import path
    
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('index/', views.index),  # 新路由
    ]
    

    app01/views.py 中编写视图:

    from django.shortcuts import render
    
    # Create your views here.
    
    def index(request):
        return render(request, 'index.html')
    

    在 app01 目录下新建文件夹templates ,并编写 index.html:

    app01/templates/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <style>
        .message{
             100%;
            height: 300px;
            border: 1px solid #dddddd;
        }
    </style>
    <body>
        <div class="message" id="message"></div>
    
        <div>
            <input type="text" id="txt">
            <!-- 添加了 onclick 事件 -->
            <input type="button" value="send" onclick="sendMessage()">
            <input type="button" value="close" onclick="ws_close()">
        </div>
    
    
    
        <script>
            // 创建 WebSocket 对象, 尝试握手连接
            socket = new WebSocket("ws://127.0.0.1:8000")
    
            // onopen 函数会在 websocket 和服务端建立连接成功后,自动调用执行
            socket.onopen = function (event){
                let tag = document.createElement("div")
                tag.innerText = '[连接成功]'
                document.getElementById('message').append(tag)
            }
    
            // onmessage 会在 websocket 接收到服务端的消息后,自动调用执行
            socket.onmessage = function (event){
                let tag = document.createElement("div")
                tag.innerText = event.data
                document.getElementById('message').append(tag)
            }
    
            // onclose 会在服务端主动发起断开时,自动调用执行
            socket.onclose = function (event){
                let tag = document.createElement("div")
                tag.innerText = '[服务端断开]'
                document.getElementById('message').append(tag)
    
            }
    
            function ws_close(){
                socket.close()  // 客户端主动关闭 websocket 连接
            }
    		
            // 点击按钮触发
            function sendMessage(){
                let content = document.getElementById('txt').value
                socket.send(content)  // 客户端向后端发消息
            }
    
        </script>
    </body>
    </html>
    

    修改 app01/consumers.py:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from channels.generic.websocket import WebsocketConsumer
    from channels.exceptions import StopConsumer
    
    clients = []
    
    
    class ChatConsumer(WebsocketConsumer):
    
        def websocket_connect(self, message):
            """这个函数是用来建立连接的。当客户端发起连接时,服务端会自动触发这个函数"""
            print("有人来了...")
            self.accept()  # 接受连接
            clients.append(self)  # 存储每个客户端连接
    
        def websocket_receive(self, message):
            """客户端发来消息时,服务端自动调用这个方法接受消息"""
            print('接收到消息', message)
    
            for client in clients:  # 遍历客户端,给每个客户端发送消息
                client.send(message['text'])  # send 方法可以发送消息
    
            if message['text'] == 'close':
                self.close()  # 可以关闭连接
                # 触发异常,就不会执行 websocket_disconnect() 方法了;如果不触发下面的异常,服务端主动调用 close() 后还会继续执行 websocket_disconnect()
                raise StopConsumer()
    
        def websocket_disconnect(self, message):
            """
            服务端主动调用 self.close() 时,或者客户端调用 close() 方法来关闭连接时,服务端自动运行这个方法,来关闭连接
            :param message:
            :return:
            """
            print('客户端断开连接了')
            raise StopConsumer()
    

    在项目目录下,命令行执行:

    python manage.py runserver
    

    打开浏览器,同时开两个窗口,都访问:http://127.0.0.1:8000/index

    你在任意一个窗口发送消息,另一个窗口同样能接收到

  • 相关阅读:
    在windows下安装mysql2 的问题解决 兰猫
    物料在XXX仓库不存在
    sapcar解压缩
    采购信息源(采购信息记录、合同、计划协议、报价)
    拓端tecdat|R语言矩阵特征值分解(谱分解)和奇异值分解(SVD)特征向量分析有价证券数据
    拓端tecdat|Python面板时间序列数据预测:格兰杰因果关系检验Granger causality test药品销售实例与可视化
    拓端tecdat|R语言分布滞后线性和非线性模型(DLNM)分析空气污染(臭氧)、温度对死亡率时间序列数据的影响
    拓端tecdat|Python在线零售数据关联规则挖掘Apriori算法数据可视化
    拓端tecdat|R语言ARIMAGARCH波动率模型预测股票市场苹果公司日收益率时间序列
    Google编码规范
  • 原文地址:https://www.cnblogs.com/wztshine/p/16126187.html
Copyright © 2020-2023  润新知