Django WebSocket笔记

1.原理

webSocket协议,是建立在http协议之上的

  • 客户端发起连接,生成一个随机字符串后发给服务器
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
...
...
  • 服务器接收,与magic_string拼接,后处理
magic_string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

v1 = "mnwFxiOlctXFN/DeMt1Amg==" + magic_string
v2 = hmac1(v1)
v3 = base64(v2)
  • 服务器返回数据
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Pragma: no-cache
Sec-WebSocket-Accept: 上面的密文
  • 收发数据,会进行加密

  • 断开连接

2.Django Clannels实现

在Django中,wsgi:默认支持;asgi:支持http+websocket

同步请求:客户端向服务器发送请求-->等待服务器响应-->处理完毕返回,客户端浏览器没有做别的事情。

异步请求:通过事件触发请求-->服务器处理请求-->处理完毕返回,但是客户端浏览器可以接着做别的事情

  • 安装模块
pip install channels
  • 配置
#setting.py
INSTALLED_APPS = [
    ...
    'channels',
]

# 指定ASGI的路由地址
ASGI_APPLICATION = 'XiangDataDisplaySys.asgi.application'
  • setting同级目录下创建/修改asgi.py
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', 'XiangDataDisplaySys.settings')#参数2:工程名.settings

application = ProtocalTypeRouter({
    "http": get_asgi_application(),							#自动找urls.py
    "websocket": URLRouter(routing.websocket_urlpatterns),	#创建routings,创建comsumers
})
  • 在setting同级目录下创建routings.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.conf.urls import url
from django.core.asgi import get_asgi_application
from XiangDataDisplaySys import routings

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

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": AuthMiddlewareStack(
        URLRouter(
            routings.websocket_urlpatterns
        )
    ),
})
  • 在app目录下创建routings.py
from django.conf.urls import re_path
from appDataDisplay import consumers

websocket_urlpatterns = [
    re_path(r'^chat-channel/',consumers.ChatConsumer.as_asgi())
]
  • 在app目录下创建consumers.py
#异步处理代码
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.exceptions import StopConsumer

CONN_LIST = []

class ChatConsumer(AsyncWebsocketConsumer):
    #groups = ["broadcast"]

    async def connect(self):
        # Called on connection.
        # To accept the connection call:
        await self.accept()
        # Or accept the connection and specify a chosen subprotocol.
        # A list of subprotocols specified by the connecting client
        # will be available in self.scope['subprotocols']
        #await self.accept("subprotocol")
        # To reject the connection, call:
        #await self.close()
        print("来了来了.....")
        CONN_LIST.append(self)
        #await self.send(text_data="要回复要回复!!!")

    async def receive(self, text_data=None, bytes_data=None):
        # Called with either text_data or bytes_data for each frame
        # You can call:
        print(text_data)
        await self.send(text_data="不要回复不要回复!!!")
        # # Or, to send a binary frame:
        # await self.send(bytes_data="Hello world!")
        # # Want to force-close the connection? Call:
        # await self.close()
        # # Or add a custom WebSocket error code!
        # await self.close(code=4123)

    async def disconnect(self, close_code):
        # Called when the socket closes
        print("失去了连接.....")
        raise StopConsumer()
        CONN_LIST.remove(self)
  • 前端javascript代码
 //链接服务器
let websocket = new WebSocket('ws://127.0.0.1:8000/msg/');
//指定事件回调
websocket.onmessage =  function(e){ 
    //var data = JSON.parse(e.data);
    //console.log(data);
    console.log(e);
}
websocket.onopen = function(e){
    console.log(e);
}
websocket.onerror = function(e){
    console.log(e);
}
websocket.onclose = function(e){
    console.log(e);
}

var interval = setInterval(function() { 
    websocket.send("你好好!!!");
}, 1000);  //5秒循环调用执行remind()函数
上一篇:红米Note 5A完美卡刷开发版获得ROOT超级权限的方法


下一篇:mysql常用的命令大全