python3 django2 channels2实现websocket服务端 以及websocket-client实现客户端

简介

WebSocket 是提供的一种在单个 TCP 连接上进行全双工通讯的协议, 其主要特点可持久性连接,数据可双向传输,服务端可以主动推送数据给客户端,数据的实时性远远好于轮训机制。

项目使用的python版本为3.7, django版本为2.2长期支持版本, chanels为2.4。

代码实现

服务端

  • 前提: 已创建好一个django项目,并创建一个app并且可以成功运行。

  • 博主项目结构, 如图所示:

在这里插入图片描述

  • 通过pip install -U channels-U参数是升级 原来已经安装的包,如果有新版本,不带U不会装新版,带上才会更新到最新版本。
  • 在settings.py的INSTALLED_APPS数组中添加channels
INSTALLED_APPS = [
    'simpleui',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app.apps.ApiConfig',
    'channels'  // 添加该行
]

settings.py同级目录下创建一个routing.py文件,该文件的作用跟urls.py类似用于注册路由,不过注册的是websocket的路由,在其中写如下代码:

from channels.routing import ProtocolTypeRouter

application = ProtocolTypeRouter({

})

  • 修改settings.py配置文件,添加以下代码:
# 这里对应刚刚创建的routing文件中的application
ASGI_APPLICATION = 'century_pass_server.routing.application'
  • 使用channels,需要一个通道层,通道层支持redis和memory,memory内存通道层适合开发使用,生产环境用redis。
    • 我电脑中已经安装了redis,使用redis通道层需要在settings.py配置文件中添加:
.....
ASGI_APPLICATION = 'century_pass_server.routing.application'

# 通道层配置
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

还需要安装一个库:pip install channels_redis。

  • 使用内存通过则修改配置文件即可:

.....
ASGI_APPLICATION = 'century_pass_server.routing.application'

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer"
    }
}
  • 然后在app目录下创建一个websocket.py文件,写上如下代码:
from channels.generic.websocket import AsyncJsonWebsocketConsumer


# 这里继承了AsyncJsonWebsocketConsumer类,该类是异步且支持接收或发送josn,实际上在WebsocketConsumer上的做的封装
class WbConsumer(AsyncJsonWebsocketConsumer):

    async def connect(self):
    	# 当客户端发起连接直接接受连接
        await self.accept()

    async def disconnect(self, code):
    	# 断开连接后会调用次方法
        print('关闭连接')

    async def receive_json(self, content, **kwargs):
    	# 收到客户端发送的信息在进行回复
        print('接收数据:', content)
	
        await self.send_json(content={
            'msg': '收到收到over!'
        })


  • 接着在app目录下创建一个routing.py, 添加如下代码:
from django.urls import path
from app.websocket import WbConsumer

websocket_urlpatterns = [
    path('ws/<int:e_id>', WbConsumer)
]
  • 接着在settings.py同级目录下的routing.py做下修改:
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import app.routing

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

客户端

客户端还是使用python来实现, 需要安装websocket-client库, 通过pip install websocket-client安装即可。
客户端代码挺简单的,也就是监听几个事件, 直接贴代码:

import json
import websocket


def on_message(ws, message):
    """
    监听消息
    :param ws:
    :param message:
    :return:
    """

    print('收到消息:', json.loads(message))

    print(ws.title)


def on_error(ws, error):
    """
    :param ws:
    :param error:
    :return:
    """
    print('出错了')


def on_close(ws):
    """
    :param ws:
    :return:
    """
    print('已关闭')


def on_open(ws):
    """
    :param ws:
    :return:
    """
    print('打开连接: ', ws.title)
    data = {
        'msg': 'hello world'
    }
    ws.send(json.dumps(data))


def start_websocket():
    """
    启动websocket服务
    :return:
    """
    websocket.enableTrace(True)
    uri = 'ws://127.0.0.1:8000/ws/1'
    ws = websocket.WebSocketApp(uri,
                                on_message=on_message,
                                on_error=on_error,
                                on_close=on_close)
    ws.on_open = on_open

    ws.title = '我是外部绑定的标题'  # 通过ws设置一个title, 在绑定方法遍可以拿到这个属性

    ws.run_forever()


if __name__ == '__main__':
    start_websocket()
`

运行

  • 服务端通过python manage.py runserver 运行即可, 客户端运行则按你实际情况了。

运行效果图:
在这里插入图片描述

说明

from channels.generic.websocket import AsyncJsonWebsocketConsumer


class WbConsumer(AsyncJsonWebsocketConsumer):

    async def connect(self):
        print(self.scope)
        print(self.scope['url_route']['kwargs'])

        await self.accept()

    async def disconnect(self, code):
        print('关闭连接')

    async def receive_json(self, content, **kwargs):
        print('接收数据:', content)

        await self.send_json(content={
            'msg': '收到收到over!'
        })
  • WbSonsumer中可以通过self.scope拿到客户端请求的信息,通过这些信息可以做websocket连接的验证,如签名验证或者token验证。

  • 客户端ws.title = 'ssss', 通过外部赋值,回调函数变可拿到外部的内容。

  • 其他详细内容可以参考官方文档。

发布了69 篇原创文章 · 获赞 119 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/ClassmateLin/article/details/104502689
今日推荐