Django与Channels实现WebSocket

WebSocket

在讲Websocket之前,先了解下 long pollajax轮询 的原理。

ajax轮询

ajax轮询的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。

long poll

long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。

ajax轮询 需要服务器有很快的处理速度和资源(速度)。long poll 需要有很高的并发,也就是说同时接待客户的能力(场地大小)。

Websocket

WebSocket是一种在单个TCP连接上进行全双工通讯的协议。WebSocket允许服务端主动向客户端推送数据。在WebSocket协议中,客户端浏览器和服务器只需要完成一次握手就可以创建持久性的连接,并在浏览器和服务器之间进行双向的数据传输。[外链图片转存失败(img-hQOZev9H-1565446193334)()]

WebSocket的请求头中重要的字段:

  • ConnectionUpgrade:表示客户端发起的WebSocket请求
  • Sec-WebSocket-Version:客户端所使用的WebSocket协议版本号,服务端会确认是否支持该版本号
  • Sec-WebSocket-Key:一个Base64编码值,由浏览器随机生成,用于升级request

WebSocket的响应头中重要的字段:

  • HTTP/1.1 101 Swi tching Protocols:切换协议,WebSocket协议通过HTTP协议来建立运输层的TCP连接
  • ConnectionUpgrade:表示服务端发起的WebSocket响应
  • Sec-WebSocket-Accept:表示服务器接受了客户端的请求,由Sec-WebSocket-Key计算得来

WebSocket协议的优点:

  • 支持双向通信,实时性更强
  • 数据格式比较轻量,性能开销小,通信高效
  • 支持扩展,用户可以扩展协议或者实现自定义的子协议(比如支持自定义压缩算法等)

WebSocket协议的优点:

  • 少部分浏览器不支持,浏览器支持的程度与方式有区别
  • 长连接对后端处理业务的代码稳定性要求更高,后端推送功能相对复杂
  • 成熟的HTTP生态下有大量的组件可以复用,WebSocket较少

WebSocket的应用场景:

  • 即时聊天通信,网站消息通知
  • 在线协同编辑,如腾讯文档
  • 多玩家在线游戏,视频弹幕,股票基金实施报价

Channels

Django本身不支持WebSocket,但可以通过集成Channels框架来实现WebSocket

Channels是针对Django项目的一个增强框架,可以使Django不仅支持HTTP协议,还能支持WebSocketMQTT等多种协议,同时Channels还整合了Djangoauth以及session系统方便进行用户管理及认证。

[外链图片转存失败(img-rV2ydJ2h-1565446193339)()]

channels中文件和配置的含义

  • asgi.py:介于网络协议服务和Python应用之间的接口,能够处理多种通用协议类型,包括HTTPHTTP2WebSocket
  • channel_layers:在settings.py中配置。类似于一个通道,发送者(producer)在一段发送消息,消费者(consumer)在另一端进行监听
  • routings.py:相当于Django中的urls.py
  • consumers.py:相当于Django中的views.py

WSGI

WSGI(Python Web Server Gateway Interface):为Python语言定义的Web服务器和Web应用程序或者框架之间的一种简单而通用的接口。

ASGI

ASGI(Asynchronous Web Server Gateway Interface):异步网关协议接口,一个介于网络协议服务和Python应用之间的标准接口,能够处理多种通用的协议类型,包括HTTPHTTP2WebSocket

WSGI是基于HTTP协议模式的,不支持WebSocket,而ASGI的诞生则是为了解决Python常用的WSGI不支持当前Web开发中的一些新的协议标准。同时,ASGI对于WSGI原有的模式的支持和WebSocket的扩展,即ASGIWSGI的扩展。

Django中使用

1、安装channels,要注意版本的对应,在channels官网中可以得到对应的django版本

pip install channels==2.1.7

2、修改settings.py文件,

# APPS中添加channels
INSTALLED_APPS = [
    'django.contrib.staticfiles',
    ... ...
    'channels',
]
# 指定ASGI的路由地址
ASGI_APPLICATION = 'webapp.routing.application' #ASGI_APPLICATION 指定主路由的位置为webapp下的routing.py文件中的application

3、setting.py的同级目录下创建routing.py路由文件,routing.py类似于Django中的url.py指明websocket协议的路由

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing
# 第一种设置的方法
from channels.security.websocket import AllowedHostsOriginValidator
application = ProtocolTypeRouter({
   
    # 普通的HTTP协议在这里不需要写,框架会自己指明
    'websocket': AllowedHostsOriginValidator(
	AuthMiddlewareStack(
    	URLRouter(
        	# 指定去对应应用的routing中去找路由
        	chat.routing.websocket_urlpatterns
    		)
		),
	)
})

# 第二种设置的方法,需要手动指定可以访问的IP
from channels.security.websocket import OriginValidator
application = ProtocolTypeRouter({
   
    # 普通的HTTP协议在这里不需要写,框架会自己指明
    'websocket': OriginValidator(
	AuthMiddlewareStack(
    	URLRouter(
        	# 指定去对应应用的routing中去找路由
        	chat.routing.websocket_urlpatterns
    		)
		),
        # 设置可以访问的IP列表
        ['*']
	)
})

ProtocolTypeRouterASIG支持多种不同的协议,在这里可以指定特定协议的路由信息,我们只使用了websocket协议,这里只配置websocket即可

AllowedHostsOriginValidator:指定允许访问的IP,设置后会去Django中的settings.py中去查找ALLOWED_HOSTS设置的IP

AuthMiddlewareStack:用于WebSocket认证,继承了Cookie MiddlewareSessionMiddleware,SessionMiddleware。djangochannels封装了djangoauth模块,使用这个配置我们就可以在consumer中通过下边的代码获取到用户的信息

def connect(self):
    self.user = self.scope["user"]

self.scope类似于django中的request,包含了请求的type、path、header、cookie、session、user等等有用的信息

URLRouter: 指定路由文件的路径,也可以直接将路由信息写在这里,代码中配置了路由文件的路径,会去对应应用下的routeing.py文件中查找websocket_urlpatterns

chat/routing.py内容如下

from django.urls import path
from chat.consumers import ChatConsumer

websocket_urlpatterns = [
    path('ws/chat/', EchoConsumer), # 这里可以定义自己的路由
    path('ws/<str:username>/',MessagesConsumer) # 如果是传参的路由在连接中获取关键字参数方法:self.scope['url_route']['kwargs']['username']
]

routing.py路由文件跟djangourl.py功能类似,语法也一样,意思就是访问ws/chat/都交给ChatConsumer处理。

4、在要使用WebSocket的应用中创建consumers.pyconsumers.py是用来开发ASGI接口规范的python应用,而Django中的view.py是用来开发符合WSGI接口规范的python应用。

首先了解下面的意思:
event loop事件循环、event handler事件处理器、sync同步、async异步

下面是一个同步的consumers.py

from channels.consumer import SyncConsumer

class EchoConsumer(SyncConsumer):
    def websocket_connect(self, event):
        self.send({
   
            'type'
  • 12
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,下面是一个简单的 Django-channels 实现 WebSocket 的示例: 首先,安装 Django-channels: ``` pip install channels ``` 然后,在 Django 的 settings.py 中添加以下配置: ```python INSTALLED_APPS = [ ... 'channels', ] ASGI_APPLICATION = 'myproject.routing.application' CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels.layers.InMemoryChannelLayer', }, } ``` 在 myproject 目录下创建一个 routing.py 文件,添加以下内容: ```python from channels.routing import ProtocolTypeRouter, URLRouter from django.urls import path from myapp.consumers import MyConsumer application = ProtocolTypeRouter({ 'websocket': URLRouter([ path('ws/', MyConsumer.as_asgi()), ]), }) ``` 在 myapp 目录下创建一个 consumers.py 文件,添加以下内容: ```python from channels.generic.websocket import AsyncWebsocketConsumer import json class MyConsumer(AsyncWebsocketConsumer): async def connect(self): await self.accept() async def disconnect(self, close_code): pass async def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] await self.send(text_data=json.dumps({ 'message': message })) ``` 在你的模板中添加以下 JavaScript 代码,用于连接 WebSocket 和发送消息: ```javascript const socket = new WebSocket('ws://' + window.location.host + '/ws/'); socket.onmessage = function(e) { const data = JSON.parse(e.data); console.log(data); }; socket.onclose = function(e) { console.error('Chat socket closed unexpectedly'); }; document.querySelector('#chat-message-input').focus(); document.querySelector('#chat-message-input').onkeyup = function(e) { if (e.keyCode === 13) { // enter, return document.querySelector('#chat-message-submit').click(); } }; document.querySelector('#chat-message-submit').onclick = function(e) { const messageInputDom = document.querySelector('#chat-message-input'); const message = messageInputDom.value; socket.send(JSON.stringify({ 'message': message })); messageInputDom.value = ''; }; ``` 最后,启动 Django 服务器,打开浏览器访问你的应用程序,进入调试器,打开控制台,你应该可以看到从服务器发送的消息。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值