Django 通道 Websockets 立即连接和断开连接

2024-03-14

首先是一些背景知识,我正在研究本教程:https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django在 Windows 64 位上,使用此处的 Vagrant 发行版:https://github.com/ServiceStack/redis-windows https://github.com/ServiceStack/redis-windows使用Python 3.4和Django 1.10

我能够很好地克隆、构建和运行该项目。问题是,当我通过浏览器访问 django 视图时,它可以正常加载聊天,但是当我在控制台中发送消息时,它说 websocket 连接然后几乎立即断开连接,并且消息不发送。如果我手动将数据输入数据库,那么当我第一次加载视图时,消息就会显示出来,但由于某种原因,javascript 应用程序无法保持 websocket 打开以发送消息进行广播。下面是相关代码:

消费者.py

import re
import json
import logging
from channels import Group
from channels.sessions import channel_session
from .models import Room

log = logging.getLogger(__name__)

@channel_session
def ws_connect(message):
    # Extract the room from the message. This expects message.path to be of the
    # form /chat/{label}/, and finds a Room if the message path is applicable,
    # and if the Room exists. Otherwise, bails (meaning this is a some othersort
    # of websocket). So, this is effectively a version of _get_object_or_404.
    try:
        prefix, label = message['path'].strip('/').split('/')
        if prefix != 'chat':
            log.debug('invalid ws path=%s', message['path'])
            return
        room = Room.objects.get(label=label)
    except ValueError:
        log.debug('invalid ws path=%s', message['path'])
        return
    except Room.DoesNotExist:
        log.debug('ws room does not exist label=%s', label)
        return

    log.debug('chat connect room=%s client=%s:%s', 
        room.label, message['client'][0], message['client'][1])

    # Need to be explicit about the channel layer so that testability works
    # This may be a FIXME?
    Group('chat-'+label, channel_layer=message.channel_layer).add(message.reply_channel)

    message.channel_session['room'] = room.label


@channel_session
def ws_receive(message):
    # Look up the room from the channel session, bailing if it doesn't exist
    try:
        label = message.channel_session['room']
        room = Room.objects.get(label=label)
    except KeyError:
        log.debug('no room in channel_session')
        print('no room in channel_session')
        return
    except Room.DoesNotExist:
        log.debug('recieved message, buy room does not exist label=%s', label)
        print('recieved message, buy room does not exist label=%s', label)
        return

    # Parse out a chat message from the content text, bailing if it doesn't
    # conform to the expected message format.
    try:
        data = json.loads(message['text'])
    except ValueError:
        log.debug("ws message isn't json text=%s", text)
        print("ws message isn't json text=%s", text)
        return

    if set(data.keys()) != set(('handle', 'message')):
        log.debug("ws message unexpected format data=%s", data)
        print("ws message unexpected format data=%s", data)
        return

    if data:
        log.debug('chat message room=%s handle=%s message=%s', 
            room.label, data['handle'], data['message'])
        print('chat message room=%s handle=%s message=%s', 
            room.label, data['handle'], data['message'])
        m = room.messages.create(**data)

        # See above for the note about Group
        Group('chat-'+label, channel_layer=message.channel_layer).send({'text': json.dumps(m.as_dict())})


@channel_session
def ws_disconnect(message):
    try:
        label = message.channel_session['room']
        room = Room.objects.get(label=label)
        Group('chat-'+label, channel_layer=message.channel_layer).discard(message.reply_channel)
    except (KeyError, Room.DoesNotExist):
        pass

chat.js

$(function() {
    // When we're using HTTPS, use WSS too.
    var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    var chatsock = new WebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);

    chatsock.onmessage = function(message) {
        var data = JSON.parse(message.data);
        var chat = $("#chat")
        var ele = $('<tr></tr>')

        ele.append(
            $("<td></td>").text(data.timestamp)
        )
        ele.append(
            $("<td></td>").text(data.handle)
        )
        ele.append(
            $("<td></td>").text(data.message)
        )

        chat.append(ele)
    };

    $("#chatform").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });
});

views.py

import random
import string
from django.db import transaction
from django.shortcuts import render, redirect
from haikunator import Haikunator
from .models import Room

def about(request):
    return render(request, "chat/about.html")

def new_room(request):
    """
    Randomly create a new room, and redirect to it.
    """
    haikunator = Haikunator()
    new_room = None
    while not new_room:
        with transaction.atomic():
            label = haikunator.haikunate()
            if Room.objects.filter(label=label).exists():
                continue
            new_room = Room.objects.create(label=label)
    return redirect(chat_room, label=label)

def chat_room(request, label):
    """
    Room view - show the room, with latest messages.
    The template for this view has the WebSocket business to send and stream
    messages, so see the template for where the magic happens.
    """
    # If the room with the given label doesn't exist, automatically create it
    # upon first visit (a la etherpad).
    room, created = Room.objects.get_or_create(label=label)

    # We want to show the last 50 messages, ordered most-recent-last
    messages = reversed(room.messages.order_by('-timestamp')[:50])

    return render(request, "chat/room.html", {
        'room': room,
        'messages': messages,
    })

模型.py

from __future__ import unicode_literals

from django.db import models
from django.utils import timezone

class Room(models.Model):
    name = models.TextField()
    label = models.SlugField(unique=True)

    def __unicode__(self):
        return self.label

class Message(models.Model):
    room = models.ForeignKey(Room, related_name='messages')
    handle = models.TextField()
    message = models.TextField()
    timestamp = models.DateTimeField(default=timezone.now, db_index=True)

    def __unicode__(self):
        return '[{timestamp}] {handle}: {message}'.format(**self.as_dict())

    # @property
    # def formatted_timestamp(self):
    #     return self.timestamp.strftime('%b %-d %-I:%M %p')

    def as_dict(self):
        return {'handle': self.handle, 'message': self.message, 'timestamp': self.formatted_timestamp}

我一直在使用 javascript,看看是否可以让 websockets 保持打开状态,我也尝试过简单的 Websocket 客户端https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo?hl=en https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo?hl=en

这和那些让我相信这与 python 代码有关的事情做了同样的事情吗?

编辑1: 这是 javascript 应用程序的开发者控制台https://i.stack.imgur.com/cDoTN.jpg https://i.stack.imgur.com/cDoTN.jpg

这是运行 daphne 后的控制台输出https://i.stack.imgur.com/xWZFm.jpg https://i.stack.imgur.com/xWZFm.jpg


渠道变化非常快,因此消费者只会发生一些细微的变化。请注意底线message.reply_channel.send({'accept': True})

消费者.py

@channel_session
def ws_connect(message):
    prefix, label = message['path'].strip('/').split('/')
    room = Room.objects.get(label=label)
    Group('chat-' + label).add(message.reply_channel)
    message.channel_session['room'] = room.label
    message.reply_channel.send({'accept': True})

@channel_session
def ws_receive(message):
    label = message.channel_session['room']
    room = Room.objects.get(label=label)
    data = json.loads(message['text'])
    m = room.messages.create(handle=data['handle'], message=data['message'])
    Group('chat-'+label).send({'text': json.dumps(m.as_dict())})

@channel_session
def ws_disconnect(message):
    label = message.channel_session['room']
    Group('chat-'+label).discard(message.reply_channel)

另外,当您使用Haikunator你需要定义它的参数。例如:

haikunator = Haikunator(
    adjectives=['custom', 'adjectives'],
    nouns=['custom', 'nouns'],
    seed='random seed'
)

haikunator.haikunate(
  delimiter='-',
  token_length=4,
  token_hex=False,
  token_chars='0123456789'
)

希望这可以帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django 通道 Websockets 立即连接和断开连接 的相关文章

  • 如何使用javascript通过类名更改html元素的值

    这是我用来更改 html 元素值的代码 a class classname href Vtech com This text to be chnage a 如何在页面加载瞬间更改此文本 看来你需要添加DOMContentLoaded或者把你
  • 为什么发送 fetch() 时我的响应数据未定义?

    我正在尝试在客户端使用 fetch 将数据发布到我的 NodeJS 服务器或从我的 NodeJS 服务器发布数据 服务器很好地收到了 post 请求 我能够记录 req 变量 但是当我 res send any data 时 客户端无法检测
  • 如何通过 libwebsocket 发送异步数据?

    我正在将 Warmcat 的 libwebsocket C 库用于小型 Websocket 服务器 我已经启动并运行了这些示例 并且可以发送数据以响应从 websocket 接收数据 例如回显发送的反向字节 但是 我无法弄清楚如何在不使用
  • 如何避免在matplotlib中调用latex(输出到pgf)

    我使用 matplotlib 及其 pgf 后端来生成包含在 LaTeX 投影仪文档中的绘图 当我使用未定义的乳胶命令时 我遇到了麻烦 但对于我的应用程序 我不需要 matplotlib 来使用 Latex 生成标签或注释 我只想要正确的
  • 查找 JavaScript 中函数参数的数量[重复]

    这个问题在这里已经有答案了 可能的重复 获取函数的元数 https stackoverflow com questions 4848149 get a functions arity 假设我有 function a x function b
  • 如何在Python中获取套接字的外部IP?

    当我打电话时socket getsockname 在套接字对象上 它返回我的机器的内部 IP 和端口的元组 但是 我想找回我的外部IP 最便宜 最有效的方式是什么 如果没有外部服务器的配合 这是不可能的 因为您和另一台计算机之间可能存在任意
  • 如何在 PyTorch 中对子集使用不同的数据增强

    如何针对不同的情况使用不同的数据增强 转换 Subset在 PyTorch 中吗 例如 train test torch utils data random split dataset 80000 2000 train and test将具
  • Python 用静态图像将 mp3 转换为 mp4

    我有x文件包含一个列表mp3我想转换的文件mp3文件至mp4文件带有static png photo 似乎这里唯一的方法是使用ffmpeg但我不知道如何实现它 我编写了脚本来接受输入mp3文件夹和一个 png photo 然后它将创建新文件
  • 如何更改Python使用的SQLite版本?

    我在 Debian 9 12 上安装了 Python 3 8 和 SQLite 3 16 2 并且需要升级到较新版本的 SQLite 我已经下载并编译了 SQLite 网站上提供的合并 并将其放入 usr bin 所以当我这样做时 sqli
  • 在 grpc python 中处理异步流请求

    我试图了解如何使用双向流处理 grpc api 使用 Python API 假设我有以下简单的服务器定义 syntax proto3 package simple service TestService rpc Translate stre
  • 检测反射 DLL 注入

    在过去的几年中 恶意软件 以及一些渗透测试工具 如 Metasploit 的 meterpreter 负载 已经开始使用反射 DLL 注入 PDF http www harmonysecurity com files HS P005 Ref
  • AngularJS 中的嵌套模块

    我有 2 个不同的 AngularJs 模块 一个 widgetContainer 和一个 widget 小部件可以显示为独立的应用程序 也可以包含在小部件容器中 一个 widgetContainer 包含 0 N 个 widget 如果我
  • 图像未显示在从 HTML 创建的 PDF 上

    我想动态创建 PDF 这意味着我将从 Google Drive 获取文件 然后将它们放入 HTML 代码中 并尝试从中创建 PDF 一切工作正常 除了图像没有显示 我现在正在做的是 从 HTML 字符串创建 HtmlOutput 获取该 H
  • 使用条件在 pandas 数据框中生成新列

    我有一个 pandas 数据框 如下所示 portion used 0 1 1 0 1 2 0 3 2 3 0 0 3 4 0 8 我想根据以下内容创建一个新专栏used列 以便df看起来像这样 portion used alert 0 1
  • “x modulo y”的结果是什么?

    引用 ECMAScript 规范第 5 2 节 符号 x modulo y y 必须是有限且非零 计算 值 k 与 y 具有相同的符号 或零 使得 abs k 因此 如果 y 为正 则 x modulo y 的结果 k 为正 无论 x 的符
  • KML 中的 JavaScript 被 Google 地球插件忽略

    我创建了一个简单的 KML 文件 该文件可以在独立的 Google 地球客户端中运行 但在 Google 地球插件中根本无法运行 无论浏览器如何
  • gstreamer 中的无缝视频循环

    我正在尝试使用 gstreamer 循环播放视频 它是 python 绑定 第一次尝试是hook EOSmessage并为管道生成搜索消息 import gi gi require version Gst 1 0 from gi repos
  • jQuery 倒计时插件 - 只显示非零周期

    我正在使用 jQuery 倒计时插件编写倒计时 我只希望它显示活动 非零 周期 例如代替 剩余时间 0 天 0 小时 13 分 20 秒 它应该只显示 13 分 20 秒 我的代码是 countdown countdown expiryUr
  • 仅使用 javascript 获取网站的正文元素

    我想检索以下网站的正文内容http sports espn go com nhl bottomline scores nhl s left1 http sports espn go com nhl bottomline scores nhl
  • 在哪里放置资源特定逻辑

    您能帮我考虑在 AngularJS 中将资源 服务 特定的业务逻辑放置在哪里吗 我觉得在我的资源上创建一些类似模型的抽象应该很棒 但我不确定如何做 API调用 gt GET customers 1 lt first name John la

随机推荐