最近完成的一个项目用到了websock+channels实现实时通讯,这里把自己的心得写下来分享分享,希望可以对有这方面的需求的朋友有所帮助。
channels是django1.9以后才出的一个新的特性,它允许Django以“通道模式”运行,通过建立通道层,来向消费者和生产者(消息发送者)之间传递消息。
安装channels:pip install channels
安装channels所依赖的通道层(一般都是redis,也可以是别的):pip install asgi_redis
在Django项目中配置channnels:
1.在settings文件的INSTALLED_APPS里面加入channels
INSTALLED_APPS = [
. . .'channels',
]2.在settings文件中加入channels通道层的配置:
CHANNEL_LAYERS = {
"default": { "BACKEND": "asgi_redis.RedisChannelLayer", "CONFIG": { "hosts":[("localhost", 6379)], }, "ROUTING": "testchannels.routing.routing", }, }解释一下这段代码:它跟DATABASES的配置有点像,BACKEND指定channels通道层由redis实现。CONFIG是IP跟redis端口。ROUTING又叫通道路由,通道路由将通道映射到消费者函数。跟 urls.py类似,当有WebSocket请求访问时,就会根据这个路径找到相应表单,调用相应的函数进行处理,按照惯例通道路由应该在routing.py里。
3.替换掉Django的基于HTTP/WSGI的请求处理器,而是使用通道。它是一个基于新兴标准ASGI(异步服务器网关接口)的, 所以我们将在asgi.py文件里定义处理器:
上面的都配置完以后就可以开始写代码了。
主要要创建2个文件——consumer.py,routing.py
routing.py:
当websocket建立连接时,会寻找websocket.connet,然后调用noGroupConsumer.ws_connect方法。
当websocket发送数据时,会寻找websocket.receive,然后调用noGroupConsumer.ws_receive方法。
当websocket断开连接时,会寻找websocket.disconnect,然后调用noGroupConsumer.ws_disconnect方法。
然后创建我的consumer文件noGroupConsumer.py:
每行代码什么意思都标注清楚了,这里就不做解释了。
测试:运行项目,然后创建一个websocket连接发送消息。
连接websocket然后发送一个“hello world”,这时会弹一个框 hello world说明channels成功。
注意图上画红圈的url跟routing里面的对照一下。
Group
上面只是最基本的websocket+channels知识。如果有很多的websocket连接,但是他们需要收到不同的消息,怎么处理呢?就比如A集合跟B集合两个websocket连接集合。A集合中的任何一个元素发了一条信息,所有元素都能收到,但是B集合根本不想收到A集合中元素发的信息,怎么办呢?channels中的Group就是解决这个问题的——把信息发送到它需要的地方。
routing.py:
consumer:groupConsumer.py:
当建立连接后,把连接存入到Group中:Group("myRoom").add(message.reply_channel)
myRoom是Group的名字。Group("myRoom").send({"text":data})就会把数据发送到加入到myRoom里面的连接。
我们可以改一下上面那个html代码
跟之前唯一不同的就是websocket url需要加上组名(Group 的name)
Ok,这样通过Group编码也完成了,但是Group名是不能变的,如何动态的连接到各个Group呢?
其实可以从message['path']里面提取出Group的名字,然后把myRoom替换掉就行
代码GitHub地址:https://github.com/shichaosc/gitskills/tree/master/jozzon