前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【全栈开发】---- 一文掌握 Websocket 原理,并用 Django 框架实现

【全栈开发】---- 一文掌握 Websocket 原理,并用 Django 框架实现

作者头像
用户11404404
发布2025-03-06 09:03:34
发布2025-03-06 09:03:34
12100
代码可运行
举报
文章被收录于专栏:Edward的专栏Edward的专栏
运行总次数:0
代码可运行

介绍

WebSocket是一种先进的通信协议,旨在通过单个长时间运行的连接实现实时双向数据交换,极大地提升了Web应用程序的交互性和响应速度。不同于传统的HTTP请求-响应模型,WebSocket在客户端与服务器之间开启了一个持久化的连接,使得双方可以随时发送文本或二进制数据,无需为每次通信重新建立连接,从而减少了延迟并提高了效率。这种特性特别适用于需要实时更新的应用场景,如在线游戏、即时通讯、金融交易监控等。WebSocket协议不仅简化了开发流程,还确保了更高效的数据传输,支持更高的并发量和更低的资源消耗,成为现代Web开发中不可或缺的技术之一。此外,随着互联网技术的发展,WebSocket正逐渐成为构建高度互动和动态Web应用的标准选择,为企业提供前所未有的用户体验改进机会。

底层原理

http 协议:

。连接 。数据传输(请求和响应) 。断开连接

websocket 协议:

。连接,客户端发起 。握手(验证),客户端发送一个消息,服务端接收到消息后做一些特殊处理并返回。服务端支持 websocket 协议 。收发数据(加密) 。断开连接

握手环节详解:

创建完链接后,客户端会自己生成一串随机字符串,并且加密后以密文的形式存储到客户端,以明文发送给服务端,服务端加密后发送给客户端,客户端比较自己加密算法得到的密文与服务端发送过来的密文是否相同,若相同,则服务端支持 websocket 协议,即握手成功,可以进行下一步操作,否则则不支持。

客户端发送给服务端的是这玩意:

GET /chatsocket HTTP/1.1 Host: 127.0.0.1:8002 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Origin: http://localhost:63342 Sec-WebSocket-Version: 13 Sec-WebSocket-Key: mnwFxiOlctXFN/DeMt1Amg== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits ... ... \r\n\r\n

服务端真正接收的是 Sec-WebSocket-Key

mnwFxiOlctXFN/DeMt1Amg==

然后将服务端将 Sec-WebSocket-Key 与 magic_string 进行字符串拼接

magic_string 有个固定值:258EAFA5-E914-47DA-95CA-C5AB0DC85B11

再将拼接的字符串进行 hmac1 加密,再进行 base64 加密

服务端将最后加密得到的结果返还给客户端,返还新式如下:

"HTTP/1.1 101 Switching Protocols\r\n" \ "Upgrade:websocket\r\n" \ "Connection: Upgrade\r\n" \ "Sec-WebSocket-Accept: 最终密文

然后客户端将服务端发送的密文和客户端自己产生的密文进行比较,相同则牵手成功。

收发数据(加密)

收发数据加密我看不懂,也不想去懂,大家可以自己搜搜视频看看。

Django 中配置 channels

django 默认不支持 websocket ,需要安装组件:

pip install channels

配置

1、注册 channels

代码语言:javascript
代码运行次数:0
复制
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "app01.apps.App01Config",
    "channels",
]

2、在 settings.py 中添加 asgi_application

代码语言:javascript
代码运行次数:0
复制
ASGI_APPLICATTON = "lang_poll.asgi.application"

这里的 lang_poll 是自己的 Django 项目名称

3、修改 asgi.py 文件

原来的 asgi.py 文件只能处理 http 请求,现在加入 websocket 后需要修改:

代码语言:javascript
代码运行次数:0
复制
"""
ASGI config for lang_poll 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/5.1/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", "lang_poll.settings")
# application = get_asgi_application()

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": URLRouter(routing.websocket_urlpatterns),
})

4、routing

asgi.py 中的 routing 是自己编写的文件,相当于 http 中的 urls.py,创建在 asgi.py 相同目录中:

代码语言:javascript
代码运行次数:0
复制
from django.urls import re_path
from app01 import consumers

websocket_urlpatterns = [
    re_path(r'ws/(?P<group>\w+)/$', consumers.ChatConsumer.as_asgi()),
]

5、consumers

这里的 consumers 也得自己创建,放在 app01 目录下,相当于 views.py ,用来编写 websocket 请求的响应逻辑:

代码语言:javascript
代码运行次数:0
复制
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer

class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self,message):
        # 客户端发送 websocket请求时,会自动触发这个函数
        # accept 函数允许客户端与服务端建立联系
        self.accept()

    def websocket_receive(self,message):
        # 客户端向服务端基于 websocket发送数据时,会自动触发该函数,并接收消息
        self.send("不要回复")
        # self.close()  是服务端主动断开连接

    def websocket_disconnect(self,message):
        # 客户端与服务端断开连接时,自动触发
        print("断开连接")
        raise StopConsumer()

实现 聊天室

前端页面可就用之前轮询的:

代码语言:javascript
代码运行次数:0
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .message{
            width: 200px;
            height: 300px;
            border: 1px solid orangered;
        }
    </style>
</head>
<body>
<div class="message" id="message"></div>
<div class="input">
    <input type="text" placeholder="请输入" id="txt">
    <input type="button" value="发送">
</div>
</body>
</html>

因为博主最近事比较多,聊天功能就不实现了,请见谅,后期会补回来的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 底层原理
    • 握手环节详解:
    • 收发数据(加密)
  • Django 中配置 channels
    • 1、注册 channels
    • 2、在 settings.py 中添加 asgi_application
    • 3、修改 asgi.py 文件
    • 4、routing
    • 5、consumers
  • 实现 聊天室
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档