一.为什么要使用Channels

  在Django中,默认使用的是HTTP通信,不过这种通信方式有个很大的缺陷,就是不能很好的支持实时通信。如果硬是要使用HTTP做实时通信的话只能在客户端进行轮询了,不过这样做的开销太大了。
  因此,在1.9版本之后,Django实现了对Channels的支持,他所使用的是WebSocket通信,解决了实时通信的问题,而且在使用WebSocket进行通信的同时依旧能够支持HTTP通信。

二.创建一个Django Channels样例的完整流程

1. 首先下载相应插件

pip install channels
pip install asgi_redis

2. 创建一个新工程

django-admin.py startproject channels_example

工程目录如下:
|-- channels_example
|    |--channels_example
|        |-- __init__.py
|        |-- settings.py
|        |-- urls.py
|        |-- wsgi.py
|    |-- manage.py

这里我们要在内层的channels_example目录下创建几个channels所需的必要文件。
包括:
routing.py
consumer.py
asgi.py

这几个文件先放着,之后我会一一介绍。
新的目录如下:
|-- channels_example
|    |--channels_example
|        |-- __init__.py
|        |-- settings.py
|        |-- urls.py
|        |-- wsgi.py
|        |-- routing.py
|        |-- consumer.py
|        |-- asgi.py
|    |-- manage.py

3. 设置settings.py中的参数

这里首先将channels加入到INSTALLED_APPS中,如下:

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels',
]

然后,添加新的参数CHANNEL_LAYERS,如下:

CHANNEL_LAYERS = {
"default": {
"BACKEND": "asgiref.inmemory.ChannelLayer",
"ROUTING": "channels_example.routing.channel_routing",
},
}

这里,需要注意的是 ROUTING 参数,他是用来指定WebSocket表单的位置,当有WebSocket请求访问时,就会根据这个路径找到相应表单,调用相应的函数进行处理。
channels_example.routing 就是我们刚才建好的routing,py文件,里面的channel_routing我们下面会进行填充。

4. 填写新的表单——routing.py文件

上一步我们已经了解到,routing.py文件其实就是个表单,功能和Django原来的urls.py文件一样,不过这里使用的不是URL,而是请求的类型。

from channels.routing import route
from channels_example import consumers #导入处理函数 channel_routing = [
#route("http.request", consumers.http_consumer), 这个表项比较特殊,他响应的是http.request,也就是说有HTTP请求时就会响应,同时urls.py里面的表单会失效 route("websocket.connect", consumers.ws_connect), #当WebSocket请求连接上时调用consumers.ws_connect函数
route("websocket.receive", consumers.ws_message), #当WebSocket请求发来消息时。。。
route("websocket.disconnect", consumers.ws_disconnect), #当WebSocket请求断开连接时。。。
]

5. 填写新的视图文件——consumers.py

上一步我们已经了解到,routing.py相当于新的urls.py,而consumers.py就相当于新的view.py。

代码:

from django.http import HttpResponse
from channels.handler import AsgiHandler #message.reply_channel 一个客户端通道的对象
#message.reply_channel.send(chunk) 用来唯一返回这个客户端 #一个管道大概会持续30s #当连接上时,发回去一个connect字符串
def ws_connect(message):
message.reply_channel.send({"connect"}) #将发来的信息原样返回
def ws_message(message):
message.reply_channel.send({
"text": message.content['text'],
})
#断开连接时发送一个disconnect字符串,当然,他已经收不到了
def ws_disconnect(message):
message.reply_channel.send({"disconnect"})

6. asgi.py文件

类似于Django自己生成的wsgi.py文件,内容如下:

import os
import channels.asgi os.environ.setdefault("DJANGO_SETTINGS_MODULE", "channels_example.settings") #这里填的是你的配置文件settings.py的位置
channel_layer = channels.asgi.get_channel_layer()

7. 发布运行

python manage.py runserver 0.0.0.0:8000

这是一个测试用的JS代码,能够发送和接收WebSocket请求:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title></title> <script type="text/javascript">
function WebSocketTest()
{
if ("WebSocket" in window)
{
alert("您的浏览器支持 WebSocket!"); socket = new WebSocket("ws://" + "localhost:8000" + "/channels_example/");
socket.onmessage = function(e) {
alert(e.data);
}
socket.onopen = function() {
socket.send("hello world");
}
// Call onopen directly if socket is already open
if (socket.readyState == WebSocket.OPEN) socket.onopen();
} else
{
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
}
</script> </head>
<body> <div id="sse">
<a href="javascript:WebSocketTest()">运行 WebSocket</a>
</div> </body>
</html>

三.进阶 —— Group

四.进阶 —— message详解

五.遇到的问题

1. 后来的请求可能会打断之前请求的执行

比如,我写了下面三个函数响应connect,send和disconnect

@channel_session
def ws_message(message):
#送给全组人
print message.channel_session['room']
Group("chat-%s" % message.channel_session['room']).send({
"text": message.content['text'],
}) @channel_session
def ws_connect(message):
room = message.content['path'].strip("/")
message.channel_session['room'] = room
Group("chat-%s" % room).add(message.reply_channel) @channel_session
def ws_disconnect(message):
print message.channel_session['room']
Group("chat-%s" % message.channel_session['room']).discard(message.reply_channel)

客户端我这样写:

socket.onopen = function() {
socket.send("hello world");
}

这样就会产生一个问题,当客户端连接到服务端时,服务端执行ws_connect()函数,然后客户端又send()了数据,服务端就会去调用ws_message()函数,而终止了ws_connect()函数的执行。

此时,我的ws_connect()函数还未对message.channel_session['room']进行赋值,而ws_message()函数就调用了他,所以会报错。

然后我尝试了断开连接,运行正常,这就说明ws_connect()函数最终还是执行完了,不过是在ws_message()函数执行之后。

综上,当服务端接收到新的请求时,可能会打断上个请求的执行,这点需要特殊注意一下。

Django Channels 学习笔记的更多相关文章

  1. Django初识 学习笔记一

    Django初识 学习笔记一 mvcviewsmodelstemplate. 一 MVC框架 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(c ...

  2. Django:学习笔记(9)——视图

    Django:学习笔记(9)——视图 基础视图 基于函数的视图,我们需要在使用条件语句来判断请求类型,并分支处理.但是在基于类的视图中,我们可以在类中定义不同请求类型的方法来处理相对应的请求. 基于函 ...

  3. Django:学习笔记(8)——文件上传

    Django:学习笔记(8)——文件上传 文件上传前端处理 本模块使用到的前端Ajax库为Axio,其地址为GitHub官网. 关于文件上传 上传文件就是把客户端的文件发送给服务器端. 在常见情况(不 ...

  4. Django:学习笔记(9)——用户身份认证

    Django:学习笔记(9)——用户身份认证 User

  5. Django:学习笔记(8)——视图

    Django:学习笔记(8)——视图

  6. Django:学习笔记(7)——模型进阶

    Django:学习笔记(7)——模型进阶 模型的继承 我们在面向对象的编程中,一个很重要的的版块,就是类的继承.父类保存了所有子类共有的内容,子类通过继承它来减少冗余代码并进行灵活扩展. 在Djang ...

  7. Django:学习笔记(6)——模型

    Django:学习笔记(6)——模型 快速上手 模型到底是什么呢?我们可以想,如果一张数据表的各个字段可以自动映射到一个类的各个属性,则每条记录对应这个类的一个对象.那我们通过类方法来操作对象(即表记 ...

  8. Django:学习笔记(5)——会话

    Django:学习笔记(5)——会话 配置中间件 Django中使用会话,需要配置一个中间件. 配置会话引擎 默认情况下,Django在数据库中存储sessions(使用了django.contrib ...

  9. Django:学习笔记(4)——请求与响应

    Django:学习笔记(4)——请求与响应 0.URL路由基础 Web应用中,用户通过不同URL链接访问我们提供的服务,其中首先经过的是一个URL调度器,它类似于SpringBoot中的前端控制器. ...

随机推荐

  1. EntityFramework简介

    EntityFramework是什么? 1.是对ADO.NET 更高封装的ORM (对象关系映射)框架,跟Nhibernate类似 2.用面向对象的方式来操作关系数据库 3.目标: 提高开发效率,减轻 ...

  2. ORACLE调整SGA_TARGET值耗费时间长案例

    在一数据库版本为(标准版)Oracle Database 10g Release 10.2.0.4.0 - 64bit Production 的服务器上调整 sga_target时,遇到命令执行了非常 ...

  3. 统计文件种类数+获取子shell返回值的其它方法

    前言 只是作为一个shell的小小练习和日常统计用,瞎折腾的过程中也是摸到了获取子shell返回值的几种方法: 肯定还有别的方法,跟进程间的通信相关,希望你能提出建议和补充,谢谢~ 完整程序: #! ...

  4. C# 记录错误日志

    程序的错误日志如何记录下来? 可以在遇到异常时,Catch异常,然后把异常的信息输出到txt文件中即可 /// <summary> /// 错误日志 /// </summary> ...

  5. OpenStack 企业私有云的若干需求(10):OpenStack 的前景和钱景

    本系列会介绍OpenStack 企业私有云的几个需求: 自动扩展(Auto-scaling)支持 多租户和租户隔离 (multi-tenancy and tenancy isolation) 混合云( ...

  6. 一个"如何使用示波器安全测试接市电电路板"的问题

    最近犯了一个错误测试操作: 测试场景:直接从市电插座取电接入3W非隔离开关电源电路板,使用示波器测试输出电压,此时示波器通过另外一个插座直接从市电取电 测试后果:在将示波器接到输出负极的一瞬间,漏电保 ...

  7. Caffe源码解析5:Conv_Layer

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ Vision_layer里面主要是包括了一些关于一些视觉上的操 ...

  8. COGS 265线段覆盖[线段树]

    265. 线段覆盖 ★★☆   输入文件:xdfg.in   输出文件:xdfg.out   简单对比时间限制:2 s   内存限制:20 MB [问题描述] 有一根长度为 L 的白色条状物.有两种操 ...

  9. Javascript函数式编程要掌握的知识点讲解

    一:理解call和apply 及arguments.callee ECMAScript3给Function的原型定义了两个方法,他们是Function.prototype.call 和 Functio ...

  10. C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 数据权限增强、范围权限增强

    并不是不想做B\S的管理工具,只是精力实在不够,由于用户权限管理组件是基础组件.所以C\S的也无妨,不会有几个人在乎Oracle,SQLServer是否不b\s的,注重的是功能性能,请大家不要纠结与是 ...