视频demo
GIFdemo
代码结构
代码细节
Talking_view/settings.py
- APP里添加了 ‘channels’
- MIDDLEWARE 里禁止了csrf
- 添加 ASGI_APPLICATION 和 CHANNEL_LAYERS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels',
'chat',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
ASGI_APPLICATION = 'Talking_view.routing.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
Talking_view/asgi.py
确定部分的加载方式.
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Talking_view.settings')
application = get_asgi_application()
Talking_view/routing.py
创建websocket,并且指定了服务指向哪个APP chat.routing.websocket_urlpatterns
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
chat/routing.py
跟django正常的添加接口的方式是一样的.
from django.urls import path, re_path
from . import consumers
websocket_urlpatterns = [
path(r'ws/chat/<from_id>/<to_id>/', consumers.As_ChatConsumer.as_asgi()),
re_path(r'', consumers.Err_ChatConsumer.as_asgi()),
]
chat/consumers.py
- T_ChatConsumer 是同步的
- As_ChatConsumer 是异步的
from channels.exceptions import StopConsumer
from channels.generic.websocket import AsyncWebsocketConsumer, WebsocketConsumer
CONSUMER_OBJECT_DICT = {}
class T_ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""
客户端浏览器发来连接请求之后就会被触发
:param message:
:return:
"""
print(self.scope)
from_id = self.scope['url_route']['kwargs']['from_id']
to_id = self.scope['url_route']['kwargs']['to_id']
self.accept()
if from_id not in CONSUMER_OBJECT_DICT:
CONSUMER_OBJECT_DICT.update({from_id: self})
self.send(text_data=str({from_id: "连接成功!"}))
print('连接', {'from_id': from_id, 'to_id': to_id, 'channel_name': self.channel_name}, self)
else:
print('请勿重复连接')
return
def websocket_receive(self, message):
"""
客户端浏览器向服务端发送消息,此方法自动触发
:param message:
:return:
"""
from_id = self.scope['url_route']['kwargs']['from_id']
to_id = self.scope['url_route']['kwargs']['to_id']
if to_id in CONSUMER_OBJECT_DICT:
values = (CONSUMER_OBJECT_DICT[to_id])
message.update({
"from_id": from_id,
"to_id": to_id
})
values.send(text_data=str(message))
self.send(text_data=str({"code": 200, "msg": "发送成功"}))
else:
self.send(text_data=str({"code": 400, "msg": "对方不在线"}))
def websocket_disconnect(self, message):
"""
客户端浏览器主动断开连接
:param message:
:return:
"""
from_id = self.scope['url_route']['kwargs']['from_id']
if from_id in CONSUMER_OBJECT_DICT:
CONSUMER_OBJECT_DICT.pop(from_id)
print('断开', {'from_id': from_id, 'channel_name': self.channel_name}, self)
raise StopConsumer()
class As_ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
from_id = self.scope['url_route']['kwargs']['from_id']
to_id = self.scope['url_route']['kwargs']['to_id']
await self.accept()
if from_id not in CONSUMER_OBJECT_DICT:
CONSUMER_OBJECT_DICT.update({from_id: self})
await self.send(text_data=str({from_id: "连接成功!"}))
print('连接', {'from_id': from_id, 'to_id': to_id, 'channel_name': self.channel_name}, self)
else:
print('请勿重复连接')
return
async def websocket_receive(self, message):
from_id = self.scope['url_route']['kwargs']['from_id']
to_id = self.scope['url_route']['kwargs']['to_id']
if to_id in CONSUMER_OBJECT_DICT:
values = (CONSUMER_OBJECT_DICT[to_id])
message.update({
"from_id": from_id,
"to_id": to_id
})
await values.send(text_data=str(message))
await self.send(text_data=str({"code": 200, "msg": "发送成功"}))
else:
await self.send(text_data=str({"code": 400, "msg": "对方不在线"}))
async def websocket_disconnect(self, message):
"""
客户端浏览器主动断开连接
:param message:
:return:
"""
from_id = self.scope['url_route']['kwargs']['from_id']
if from_id in CONSUMER_OBJECT_DICT:
CONSUMER_OBJECT_DICT.pop(from_id)
print('断开', {'from_id': from_id, 'channel_name': self.channel_name}, self)
raise StopConsumer()
class Err_ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
print("强制断开连接")
await self.close()
raise StopConsumer()
用到的库及版本
aioredis==1.3.1
asgiref==3.5.2
async-timeout==4.0.2
attrs==21.4.0
autobahn==22.4.2
Automat==20.2.0
certifi==2022.6.15
cffi==1.15.0
channels==3.0.4
channels-redis==3.4.0
charset-normalizer==2.0.12
constantly==15.1.0
cryptography==37.0.2
daphne==3.0.2
Django==3.2.9
django-cors-headers==3.12.0
hiredis==2.0.0
hyperlink==21.0.0
idna==3.3
incremental==21.3.0
msgpack==1.0.3
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.21
pymongo==4.1.1
pyOpenSSL==22.0.0
pytz==2022.1
requests==2.28.0
service-identity==21.1.0
six==1.16.0
sqlparse==0.4.2
Twisted==22.4.0
twisted-iocpsupport==1.0.2
txaio==22.2.1
typing_extensions==4.2.0
urllib3==1.26.9
zope.interface==5.4.0
总结
这个是不需要操作什么试图函数之类的,就正常的编写处理数据即可.(consumers.py). 无论是同步还是异步都是可以的,在一定量级的情况下,没有什么体验差别. Err_ChatConsumer 这个是将 非法请求拦截在了这里,因为在上面的demo中我是固定了格式的.
|