15-django websocker
什么是websocker
WebSocket是一种在单个TCP连接上进行全双工通讯的协议。WebSocket允许服务端主动向客户端推送数据。在WebSocket协议中,客户端浏览器和服务器只需要完成一次握手就可以创建持久性的连接,并在浏览器和服务器之间进行双向的数据传输。
现在,很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
websocker有什么用
例如在Django中遇到一些耗时较长的任务我们通常会使用Celery来异步执行,那么浏览器如果想要获取这个任务的执行状态,在HTTP协议中只能通过轮训的方式由浏览器不断的发送请求给服务器来获取最新状态,这样发送很多无用的请求不仅浪费资源,还不够优雅,如果使用WebSokcet来实现就很完美了
WebSocket的另外一个应用场景就是下文要说的聊天室,一个用户(浏览器)发送的消息需要实时的让其他用户(浏览器)接收,这在HTTP协议下是很难实现的,但WebSocket基于长连接加上可以主动给浏览器发消息的特性处理起来就游刃有余了
django安装使用websokcer
Django本身不支持WebSocket,但可以通过集成Channels框架来实现WebSocket
pip install channels==2.3.1
进入settings.py文件,引入channels

在settings.py文件后面添加 ASGI_APPLICATION = 'websocket.routing.application'
ASGI_APPLICATION = 'websocket.routing.application' # 将信息存入redis # CHANNEL_LAYERS = { # 'default': { # 'BACKEND': 'channels_redis.core.RedisChannelLayer', # 'CONFIG': { # "hosts": [('192.168.16.27', 6379)], # redis://:password@127.0.0.1:6379/0 # }, # }, # }
创建routing文件
from channels.routing import ProtocolTypeRouter,URLRouter from django.conf.urls import url from app01 import consumers application = ProtocolTypeRouter({ # (http->django views is added by default) 'websocket': URLRouter([ ]) })
运行django你会发现如下内容

本质:channels会把原来只支持http协议的wsgi,换成支持http和websocker协议的asgi
聊天室的实现
# url url(r'^index/',views.index) #视图编写 def index(request): return render(request,'index.html')
此时你也许会懵,为啥有两个url.第一个url给用户展示页面用,第二个用于发送websocker而使用的url
修改routing文件
from channels.routing import ProtocolTypeRouter,URLRouter from django.conf.urls import url from app01 import consumers application = ProtocolTypeRouter({ # (http->django views is added by default) 'websocket': URLRouter([ url(r'^chat/$', consumers.ChatConsumer), ]) })
创建consumers文件

from channels.generic.websocket import WebsocketConsumer USER_LIST = [] class ChatConsumer(WebsocketConsumer): def connect(self): '''有新的连接执行''' print('有人来连接了') USER_LIST.append(self) self.accept() def receive(self, text_data=None, bytes_data=None): '''客户端发来数据执行''' print('有人发来数据了') print(text_data) for obj in USER_LIST: obj.send(text_data=text_data) def disconnect(self, code): '''和客户端连接断开执行''' print('有人断开连接了') USER_LIST.remove(self)
html
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>聊天页面</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"> <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css'> <link rel="stylesheet" href="/static/dist/style.css"> </head> <body> <div class="chat"> <div class="chat-header clearfix"> <img src="/static/img/123.png" alt="avatar"/> <div class="chat-about"> <div class="chat-with">聊天室</div> </div> </div> <div class="chat-history"> <ul> <li id="content"> </li> </ul> </div> <div class="chat-message clearfix"> <textarea name="message-to-send" id="message-to-send" placeholder="Type your message" rows="3"></textarea> <button onclick="sendMsg()">Send</button> </div> </div> <script> ws = new WebSocket('ws://127.0.0.1:8000/chat/'); ws.onmessage = function (event) { console.log(event.data); var tag = document.createElement('div'); tag.innerText = event.data; tag.className = 'message my-message'; document.getElementById('content').appendChild(tag); }; function sendMsg() { var msg = document.getElementById('message-to-send').value; ws.send(msg); document.getElementById('message-to-send').value = ""; } </script> <script src='/static/dist/handlebars.min.js'></script> <script src='/static/dist/list.min.js'></script> <script src="/static/dist/script.js"></script> </body> </html>
展示


浙公网安备 33010602011771号