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

目录

介绍

底层原理

握手环节详解:

收发数据(加密)

[Django 中配置 channels](#Django 中配置 channels)

[1、注册 channels](#1、注册 channels)

[2、在 settings.py 中添加 asgi_application](#2、在 settings.py 中添加 asgi_application)

[3、修改 asgi.py 文件](#3、修改 asgi.py 文件)

4、routing

5、consumers

[实现 聊天室](#实现 聊天室)


介绍

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

python 复制代码
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

python 复制代码
ASGI_APPLICATTON = "lang_poll.asgi.application"

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

3、修改 asgi.py 文件

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

python 复制代码
"""
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 相同目录中:

python 复制代码
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 请求的响应逻辑:

python 复制代码
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()

实现 聊天室

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

python 复制代码
<!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>

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

相关推荐
数据知道35 分钟前
网络安全实战:子域名接管实战——从 CNAME 配置错误到完全控制
网络·安全·web安全·网络安全
lf13210271 小时前
用 JSON Schema 管装修节点记录:从照片台账到可校验工程数据
网络·数据库·人工智能·经验分享·物联网·json·智能家居
LayZhangStrive1 小时前
后端通识 - 远程服务调用RPC
网络·网络协议·rpc·sentinel·openfeign·远程服务调用
华清远见成都中心3 小时前
FreeRTOS事件组(Event Group)的工作机制分析
服务器·网络·网络协议
xiaoxiangsiyan3 小时前
RHCE2026云原生路线EX188和EX288完整备考指南
运维·网络·云原生·自动化
西安景驰电子3 小时前
《PTP精确时间协议系列》第二篇:工程部署、调试与性能优化
运维·服务器·网络·数据库·windows·性能优化
tiantianuser4 小时前
NVME-oF IP 设计15 : 适于高速网络存储系统的IP设计1
网络协议·rdma·高速传输·cmac·roce v2
虹科网络安全4 小时前
KnowBe4 SAT 是什么?安全意识培训平台功能与应用详解
网络
艺杯羹5 小时前
古典密码学攻防演进全景:从凯撒移位、频率分析到一次一密与恩尼格玛机破译
网络·人工智能·安全·网络安全·密码学·密码安全
发量惊人的中年网工5 小时前
多品牌酒店门店如何集中管控网络?SD-WAN 实现住客网与业务网隔离的实践
网络·组网