python-websocket-channels-单对单聊天

视频demo

测试websocket发送信息

GIFdemo

python-websocket-channels-单对单聊天

; 代码结构

python-websocket-channels-单对单聊天

代码细节

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///', 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中我是固定了格式的.

Original: https://blog.csdn.net/Ly_Word/article/details/125798127
Author: L’y
Title: python-websocket-channels-单对单聊天

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/734247/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球