Django插件Channels ——实现即时通信
注明
本笔记主要参考《Django应用开发实战》《Django企业开发实战》,这两本书前者详细,后者精炼。学习之后真的是感觉自己进步了很多。值得一读,如果您遇到了值得一读的书籍,欢迎推荐给我,大家共同进步。
@[TOC](文章目录)
前言
Web聊天室的实现方法有多种,下面将简要介绍一下实现方法
- AJAX技术利用AJAX实现网页与服务器的无刷新交互。缺点是实时性不高。
- Coment技术Coment是一种Web应用框架,服务器以异步方式向浏览器推送数据,无需浏览器发送请求,非常适合事件驱动的Web应用,以及对交互性和实时性要求较高的应用。
- XMPP协议:可扩展消息处理协议,专为及时通信系统设计的通信协议,用于即时消息以及在线探测
- Flash的XmlSocket:Flash Media Server 是一个强大的流媒体服务器,它基于RTMP协议,提供了稳定的流媒体交互功能,内置远程共享对象的机制,是浏览器创建并连接服务器的远程共享
- websocket协议:WebSocket是一种在单个TCP连接上进行全双工通信的协议WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket
API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输
django实现websocket大致上有两种方式,一种channels,一种是dwebsocket。channels依赖于redis,twisted等
提示:以下是本篇文章正文内容,下面案例可供参考
一、Channels?
Channels安装与配置
pip install channels
pip channels_redis
pip install pypiwin32
settings配置
INSTALLED_APPS = [
'django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','channels', # 添加channels功能'chat',
]
ASGI_APPLICATION = '项目名.routing.application'
CHANNEL_LAYERS = {'default': {'BACKEND': 'channels_redis.core.RedisChannelLayer','CONFIG': {"hosts": [('127.0.0.1', 6379)],},},
}
说明:
- CHANNEL_LAYERS用于设置Redis数据库的连接方式.
- ASGI_APPLICATION:代表routing.py定义的application对象。
项目名文件夹下定义routing.py
from channels.routing import ProtocolTypeRouter
from channels.routing import URLRouter
from .urls import websocket_urlpatternsapplication = ProtocolTypeRouter({# (http->django views is added by default)'websocket': AuthMiddlewareStack(URLRouter(websocket_urlpatterns)),
})
说明:
定义这个文件是为了响应ASGI_APPLICATION定义application对象,将Django与该插件建立连接。
在项目名文件夹下urls.py,定义websocket_urlpatterns
from django.urls import path, include
from .consumers import ChatConsumer
urlpatterns = [path('', include(('chat.urls', 'chat'), namespace='chat'))
]websocket_urlpatterns = [path('ws/chat//' , ChatConsumer),
]
说明:
- websocket_urlpatterns用于定义Channels的路由信息,上数定义的路由ws/chat/
/,它是由consumers.py的ChatConsumer处理和响应HTTP请求的,该路由作为Channels的API接口由网页的Javascript与该路由构建通信连接,使浏览器和服务器之间相互传递数据。
最后定义consumers.py
# from asgiref.sync import async_to_sync
# from channels.generic.websocket import WebsocketConsumer
# import json
#
# # 将消费者代码为同步。
# class ChatConsumer(WebsocketConsumer):
# def connect(self):
# self.room_name = self.scope['url_route']['kwargs']['room_name']
# self.room_group_name = 'chat_%s' % self.room_name
#
# # Join room group
# async_to_sync(self.channel_layer.group_add)(
# self.room_group_name,
# self.channel_name
# )
#
# self.accept()
#
# def disconnect(self, close_code):
# # Leave room group
# async_to_sync(self.channel_layer.group_discard)(
# self.room_group_name,
# self.channel_name
# )
#
# # Receive message from WebSocket
# def receive(self, text_data):
# text_data_json = json.loads(text_data)
# message = text_data_json['message']
#
# # Send message to room group
# async_to_sync(self.channel_layer.group_send)(
# self.room_group_name,
# {
# 'type': 'chat_message',
# 'message': message
# }
# )
#
# # Receive message from room group
# def chat_message(self, event):
# message = event['message']
#
# # Send message to WebSocket
# self.send(text_data=json.dumps({
# 'message': message
# }))#-------------low------------
# 将消费者代码重写为异步,以提高其性能。
from channels.generic.websocket import AsyncWebsocketConsumer
import jsonclass ChatConsumer(AsyncWebsocketConsumer):async def connect(self):self.room_name = self.scope['url_route']['kwargs']['room_name']self.room_group_name = 'chat_%s' % self.room_name# Join room groupawait self.channel_layer.group_add(self.room_group_name,self.channel_name)await self.accept()async def disconnect(self, close_code):# Leave room groupawait self.channel_layer.group_discard(self.room_group_name,self.channel_name)# Receive message from WebSocketasync def receive(self, text_data):text_data_json = json.loads(text_data)message = text_data_json['message']# Send message to room groupawait self.channel_layer.group_send(self.room_group_name,{'type': 'chat_message','message': message})# Receive message from room groupasync def chat_message(self, event):message = event['message']# Send message to WebSocketawait self.send(text_data=json.dumps({'message': message}))
下面可以很简单的实现在线聊天功能
大致思路:在应用urls中设置两个路由:创建聊天和进入聊天室。在创建聊天室后即跳转到进入聊天室路由。进入聊天室路由网页设置:使网页与项目插件连接,设置接收和发送信息(也可以设置异常事件触发器)。下面步骤
chat urls
from django.urls import path
from .views import *urlpatterns = [# 用于开启新的聊天室path('', newChat, name='newChat'),# 创建聊天室path('/' , room, name='room'),
]
chat views
from django.shortcuts import render
# 用于创建或进入聊天室
def newChat(request):return render(request, 'chat.html', locals())# 创建聊天室
def room(request, room_name):return render(request, 'room.html', locals())
chat.html(截取部分重要)
<body><div>请输入聊天室名称</div><br/><input id="input" type="text" size="30"/><br/><input id="submit" type="button" value="进 入"/><script>document.querySelector('#input').focus();document.querySelector('#input').onkeyup = function(e) {if (e.keyCode === 13) { // enter, returndocument.querySelector('#submit').click();}};document.querySelector('#submit').onclick = function(e) {var roomName = document.querySelector('#input').value;window.location.pathname = '/' + roomName + '/';};</script>
</body>
说明:
确定聊天室名称后,单击进入或者回车将触发javaScript脚本。
room.html
<body><textarea id="chat-log" cols="50" rows="6"></textarea><br/><input id="input" type="text" size="50"/><br/><input id="submit" type="button" value="发 送"/>
</body>
<script>var roomName = '{{ room_name }}';var chatSocket = new WebSocket('ws://' + window.location.host +'/ws/chat/' + roomName + '/');chatSocket.onmessage = function(e) {var data = JSON.parse(e.data);var message = data['message'];document.querySelector('#chat-log').value += (message + '\n');};chatSocket.onclose = function(e) {console.error('Chat socket closed unexpectedly');};document.querySelector('#input').focus();document.querySelector('#input').onkeyup = function(e) {if (e.keyCode === 13) { // enter, returndocument.querySelector('#submit').click();}};document.querySelector('#submit').onclick = function(e) {var messageInputDom = document.querySelector('#input');var message = messageInputDom.value;chatSocket.send(JSON.stringify({'message': message}));messageInputDom.value = '';};
</script>
说明:var chatSocket部分为了网页与项目插件连接chatSocket.onmessage接收数据,并展示到文本框chatSocket.onclose关闭连接,当出现异常时触发document.querySelector发送数据querySelector将文本展示到网页textarea组件中。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
