django实现websocket

django实现websocket

简述

简述:django实现websocket,之前django-websocket退出到3.0之后,被废弃。官方推荐大家使用channels。

channels通过升级http协议 升级到websocket协议。保证实时通讯。也就是说,我们完全可以用channels实现我们的即时通讯。而不是使用长轮询和计时器方式来保证伪实时通讯。

他通过改造django框架,使django既支持http协议又支持websocket协议。

官方文档地址:https://channels.readthedocs.io/en/stable/

创建项目名为webapp 的django项目,目录结构如下

project
    - webapp
        - __init__.py
        - settings.py
        - urls.py
        - wsgi.py
    - manage.py

按照第三方库

python本身只支持http协议 使用websocket需要下载第三方库

pip install -U channels
'''
	默认下载最新版,django版本也会变为3.2
	如果不想变更django版本执行pip install -U channels==2.3
'''
在django2.2以上版本会内置支持ASGI
安装在windows机器的时候。需要自信的C++支持,报错的时候,报错有地址告诉你下载URL

配置

需要在seting.py里配置,将我们的channels加入INSTALLED_APP里。

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    ...
    'channels',
)


ASGI_APPLICATION = 'webapp.routing.application'

'''
	ASGI_APPLICATION 指定主路由的位置为webapp下的routing.py文件中的application
        ASGI_APPLICATION = '项目名同名的文件名.文件夹下py文件名默认就叫routing.该py文件内部的变量名默认就叫application'
'''

创建routing.py路由文件

setting.py的同级目录下创建routing.py路由文件,routing.py类似于Django中的url.py指明websocket协议的路由

from channels.routing import ProtocolTypeRouter

application = ProtocolTypeRouter({
    # 暂时为空,下文填充
})

启动项目

'''
	wsgi,只支持http请求
	asgi,wsgi+异步+websockt
'''

出现上图及配置完成

使用

假设你已经创建好了一个叫chat的app,并添加到了settings.py的INSTALLED_APPS中,app的目录结构大概如下
chat
    - migrations
        - __init__.py
    - __init__.py
    - admin.py
    - apps.py
    - models.py
    - tests.py
    - views.py

url:

from django.urls import path
from chat.views import chat

urlpatterns = [
    path('chat', chat, name='chat-url')
]

views:

from django.shortcuts import render

def chat(request):
    return render(request, 'chat/index.html')

接下来我们利用Channels的WebSocket协议实现消息的发送接收功能

首先需要建立一个django项目。其中在你自己的app下面 生成consumers.py和routing.py配置文件。
consumers.py:相当于django的视图,也就是说所有的websocket路由过来的执行的函数都在consumers.py类似于django的视图views.py
routing.py:是websocket中的url和执行函数的对应关系。相当于django的urls.py,根据映射关系,当websocket的请求进来的时候,根据用户的请求来触发我们的consumers.py里的方法。

1. 先从路由入手,上边我们已经创建了routing.py路由文件,现在来填充里边的内容

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})

    ProtocolTypeRouter: ASIG支持多种不同的协议,在这里可以指定特定协议的路由信息,我们只使用了websocket协议,这里只配置websocket即可

    AuthMiddlewareStack: django的channels封装了django的auth模块,使用这个配置我们就可以在consumer中通过下边的代码获取到用户的信息

    def connect(self):
        self.user = self.scope["user"]

    self.scope类似于django中的request,包含了请求的type、path、header、cookie、session、user等等有用的信息

    URLRouter: 指定路由文件的路径,也可以直接将路由信息写在这里,代码中配置了路由文件的路径,会去chat下的routeing.py文件中查找
    websocket_urlpatterns,chat/routing.py内容如下

    from django.urls import path
    from chat.consumers import ChatConsumer

    websocket_urlpatterns = [
        path('ws/chat/', ChatConsumer),
    ]

    routing.py路由文件跟django的url.py功能类似,语法也一样,意思就是访问ws/chat/都交给ChatConsumer处理

2.接着编写consumer,consumer类似django中的view,内容如下

from channels.generic.websocket import WebsocketConsumer
import json

class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.accept()

    def disconnect(self, close_code):
        pass

    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = '运维咖啡吧:' + text_data_json['message']

        self.send(text_data=json.dumps({
            'message': message
        }))
        
这里是个最简单的同步websocket consumer类,connect方法在连接建立时触发,disconnect在连接关闭时触发,receive方法会在收到消息后触发。整个ChatConsumer类会将所有收到的消息加上“运维咖啡吧:”的前缀发送给客户端
from channels.generic.websocket import WebsocketConsumer


class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self, message):
        """客户端请求建立链接时 自动触发"""
        pass


    def websocket_receive(self, message):
        """客户端发送数据过来  自动触发"""
        pass


    def websocket_disconnect(self, message):
        """客户端断开链接之后  自动触发"""
        pass

3.最后再Vue中添加websocket支持

<script>
  export default {
    name : 'test',
    data() {
      return {
        websock: null,
      }
    },
    created() {
      this.initWebSocket();
    },
    destroyed() {
      this.websock.close() //离开路由之后断开websocket连接
    },
    methods: {
      initWebSocket(){ //初始化weosocket
        const wsuri = "ws://127.0.0.1:8080";
        this.websock = new WebSocket(wsuri);
        this.websock.onmessage = this.websocketonmessage;
        this.websock.onopen = this.websocketonopen;
        this.websock.onerror = this.websocketonerror;
        this.websock.onclose = this.websocketclose;
      },
      websocketonopen(){ //连接建立之后执行send方法发送数据
        let actions = {"test":"12345"};
        this.websocketsend(JSON.stringify(actions));
      },
      websocketonerror(){//连接建立失败重连
        this.initWebSocket();
      },
      websocketonmessage(e){ //数据接收
        const redata = JSON.parse(e.data);
      },
      websocketsend(Data){//数据发送
        this.websock.send(Data);
      },
      websocketclose(e){  //关闭
        console.log('断开连接',e);
      },
    },
  }
</script>


'''
	onopen: 当浏览器和websocket服务端连接成功后会触发onopen消息

    onerror: 如果连接失败,或者发送、接收数据失败,或者数据处理出错都会触发onerror消息

    onmessage: 当浏览器接收到websocket服务器发送过来的数据时,就会触发onmessage消息,参数e包含了服务端发送过来的数据

    onclose: 当浏览器接收到websocket服务器发送过来的关闭连接请求时,会触发onclose消息	
'''

最终chat结构

chat
    - migrations
        - __init__.py
    - __init__.py
    - admin.py
    - apps.py
    - models.py
    - tests.py
    - views.py
    - rouging.py
    - consumer.py
posted @ 2022-10-28 11:51  春游去动物园  阅读(837)  评论(0编辑  收藏  举报