目录
[Django 中配置 channels](#Django 中配置 channels)
[1、注册 channels](#1、注册 channels)
[2、在 settings.py 中添加 asgi_application](#2、在 settings.py 中添加 asgi_application)
[3、修改 asgi.py 文件](#3、修改 asgi.py 文件)
[实现 聊天室](#实现 聊天室)
介绍
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>
因为博主最近事比较多,聊天功能就不实现了,请见谅,后期会补回来的。