django项目使用websocket

63 阅读3分钟

最近项目中需要用到websocket,先写个小demo了解一下基础使用。

理论知识

1、uWSGI和Daphne uWSGI和Daphne是两个不同的Web服务器,它们都可以用于运行Django应用程序,但在不同的环境和场景下使用。

  • uWSGI: uWSGI是一个全功能的Web服务器,它支持多种协议和接口规范,包括WSGI、FastCGI、HTTP等。它可以作为独立的Web服务器运行,也可以与其他Web服务器(如Nginx)配合使用。uWSGI可以处理WSGI应用程序的请求和响应,并提供了一些高级功能,如负载均衡、多进程管理和缓存等。在传统的Web应用程序中,uWSGI通常被用作生产环境的Web服务器。
  • Daphne: Daphne是基于ASGI(Asynchronous Server Gateway Interface)规范的Web服务器,它专门用于运行异步Web应用程序,如Django Channels。ASGI是一种更加通用的接口规范,允许Web应用程序处理异步请求和响应,包括WebSocket连接、长轮询和服务器推送等。Daphne是Django Channels官方推荐的服务器,它可以在支持ASGI的环境中使用。在需要处理实时通信的Django应用程序中,Daphne是常用的选择。 综上所述,uWSGI是一个全功能的Web服务器,可以用于运行传统的WSGI应用程序,而Daphne是专用于运行基于ASGI的异步Web应用程序的服务器,如Django Channels。选择使用哪个服务器取决于你的应用程序的特性和需求。

2、asgi和wsgi WSGI(Web Server Gateway Interface)和ASGI(Asynchronous Server Gateway Interface)都是Python Web应用程序与Web服务器之间的接口标准,用于处理HTTP请求和响应。

  • WSGI: WSGI是Python Web应用程序的标准接口,旨在定义Web应用程序和Web服务器之间的通信协议。它使用简单的函数调用来处理请求和生成响应。WSGI应用程序接收一个包含请求信息的字典作为参数,并返回一个包含响应信息的可迭代对象。WSGI服务器负责将请求信息传递给WSGI应用程序,并将响应发送回客户端。
  • ASGI: ASGI是一种新一代的Python Web应用程序接口,专注于支持异步(asynchronous)和高性能的Web应用程序。它允许Web应用程序使用异步编程模型,例如使用async/await关键字和异步IO操作。ASGI应用程序接收一个包含请求信息的对象作为参数,并返回一个包含响应信息的对象。ASGI服务器负责将请求信息传递给ASGI应用程序,并将响应发送回客户端。 虽然WSGI在过去是Python Web应用程序的主要接口标准,但随着异步编程的兴起和对高性能的需求,ASGI逐渐受到重视并得到广泛应用。ASGI允许开发者使用异步框架(如Django Channels)来处理实时通信、长轮询等场景。

版本

django==4.2.4

channels==4.0.0

daphne==4.0.0

Channels是一个采用Django并将其能力扩展到HTTP之外的项目,用于处理WebSockets、聊天协议、物联网协议等。它建立在ASGI的Python规范之上。

Daphne是Django软件基金会开发的一个基于ASGI (HTTP/WebSocket)的服务器,可以用来启动我们的应用,因为默认启动方式是WSGI。

# 在settings.py同级目录增加文件asgi.py
import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application

from wsdemo.routing import websocket_urlpatterns

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djangoProject1.settings")

# application = get_asgi_application()

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    'websocket': AuthMiddlewareStack(URLRouter(websocket_urlpatterns)),
})
# settings.py
INSTALLED_APPS = [
    ...
    'daphne',
    'channels',
    'wsdemo'
    ...
]

# 添加
ASGI_APPLICATION = 'djangoProject1.asgi.application'


# 添加
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer",  # 使用内存通道层作为示例,实际使用时可以根据需要选择合适的后端
    },
}

在wsdemo的app里添加文件下面的文件

#consumer.py

import json
from channels.generic.websocket import WebsocketConsumer

class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.accept()

    def disconnect(self, close_code):
        pass

    def receive(self, text_data):
        # text_data_json = json.loads(text_data)
        # message = text_data_json["message"]

        # 设置ensure_ascii以支持中文
        self.send(text_data=json.dumps({"message111": text_data}, ensure_ascii=False))

#routing.py
import json

from channels.generic.websocket import WebsocketConsumer


class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.accept()

    def disconnect(self, close_code):
        pass

    def receive(self, text_data):
        # text_data_json = json.loads(text_data)
        # message = text_data_json["message"]

        # 设置ensure_ascii以支持中文
        self.send(text_data=json.dumps({"message111": text_data}, ensure_ascii=False))

# template/index.html
<!DOCTYPE html>
<html>
<head>
  <title>WebSocket Example</title>
</head>
<body>
  <input type="text" id="messageInput" placeholder="Enter message">
  <button onclick="sendMessage()">Send</button>
  <ul id="messageList"></ul>
  <script>
    var ws = new WebSocket('ws://localhost:8999/ws/chat/');
    ws.onopen = function() {
      console.log('WebSocket connected');
      // 在连接成功后执行的操作
    };
    ws.onmessage = function(event) {
      console.log('Received message:', event.data);
      // 处理接收到的消息
      var messageList = document.getElementById('messageList');
      var li = document.createElement('li');
      li.innerText = event.data;
      messageList.appendChild(li);
    };
    ws.onclose = function() {
      console.log('WebSocket disconnected');
      // 在连接关闭后执行的操作
    };
    function sendMessage() {
      var messageInput = document.getElementById('messageInput');
      var message = messageInput.value;
      ws.send(message);
      messageInput.value = ''; // 清空输入框
    }
  </script>
</body>
</html>

启动项目 daphne -p 8999 djangoProject1.asgi:application

在浏览器运行index.html文件

image.png