django+channels+websocket完成一个实时推送系统
前言
因公司项目需求,需要建立一个展示网站,接入两台摄像机,当摄像机的照片流传过来的时候,实时展示到网页中,所以需要做一个实时推送系统的小demo,因接触django时间不长(两周左右),也算边做边学习了,网上用channels做实时聊天系统的较多,实时推送系统的比较少。
好了,进入正题。demo采用pycharm+django开发,具体用到的库有:channels、channels_redis。关于项目建立的步骤自行百度,不多赘述,pycharm建立django项目的时候已经帮你建立好了虚拟环境,很多事情基本上不需要你做了,直接码代码就可以了!!!
(下面示例的项目名称(project:mysite,app:myapp)
项目配置
1、先添加相关库
工具栏File–>Settings–>Project:(mysite)–>Project Interpreter–>±->channels+channel-redis
特别注意,channels-redis版本选择2.4.2,选择3.0.1会和本地redis服务器冲突,原因不详。
2、修改项目settings
将你创建的app和channels一并添加进去
因为使用channels_redis,咱们就一并修改了
ASGI_APPLICATION = 'mysite.routing.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
3、修改路由
(也可以不做这一步,只是为了让项目路由分类更加清晰,便于后期维护)
添加app路由
在myapp的目录下创建一个urls.py文件
/myapp/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
]
然后在项目路由下导入你的app路由
/mysite/urls.py
from django.conf.urls import include
from django.urls import path
urlpatterns = [
path('', include('myapp.urls')),
]
以上这一步等于直接在
/mysite/urls.py 修改
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
]
4、添加asgi应用路由
咱们在settings已经修改了ASGI_APPLICATION = ‘mysite.routing.application’
因此在/mysite/新建一个routing.py
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import myapp.routing
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
myapp.routing.websocket_urlpatterns
)
),
})
这里简单的解释一下:它使您可以根据中type存在的值将其分派到许多其他ASGI应用程序 之一scope。协议将定义其作用域包含的固定类型值,因此您可以使用它来区分传入的连接类型。
简而言之就是根据你的需求指向不同的url(连接的是你的视图函数)
接着添加应用的路由
即/myapp/routing.py
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('image/', consumers.PushConsumer),
]
5、创建后台的推送函数
在myapp目录下创建consumers.py
/myapp/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
# 推送consumer
class PushConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.group_name = 'image'
await self.channel_layer.group_add(
self.group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(
self.group_name,
self.channel_name
)
# print(PushConsumer.chats)
async def push_message(self, event):
await self.send(text_data=json.dumps({
"message": event['message']
}))
# 构建函数,便于外部调用
def push(username, message):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
username,
{
"type": "push.message",
"message": message
}
)
6、不要忘了我们的视图函数view.py
from django.shortcuts import render
from .consumers import push
# Create your views here.
def index(request):
for i in range(10):
push('image',i)
return render(request, 'index.html')
这里举了一个简单调用的例子
for i in range(10):
push(‘image’,i)
向image组的所有成员推送0,1、2、3…9
就是那么简单
7、在网页建立我们的websocket连接
建立一个index.html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>接收端</title>
</head>
<body>
<textarea id="log" cols="100" rows="20"></textarea><br>
<script>
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+'/image/'
);
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#log').value += (data.message + '\n');
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
</script>
</body>
</html>
这样就建立好websocket连接了
测试
打开本地的redis服务器,打开方法请自行百度下载并打开进行测试
就是下面这个东东
官网下载过慢,慢到让你窒息,别傻傻的等,请自行寻找国内资源。
如果是采用的本地测试,直接在本地打开几个网页,默认的为127.0.0.1:8000。基本效果就是没打开一个网页,上一个网页就是打印0-9的数字
如果是采用局域网的方法
在settings.py文件中修改
ALLOWED_HOSTS = [你本地电脑的IP地址]
这样就可以在同一局域网的另一台电脑打开网页进行测试,效果和本地测试相同。
以上,菜鸟一枚,欢迎指正,哈哈~
如果有不懂的可以多多查看官方文档:channels官方文档
相关文档