WebSocket 是提供的一种在单个 TCP 连接上进行全双工通讯的协议, 其主要特点可持久性连接,数据可双向传输,服务端可以主动推送数据给客户端,数据的实时性远远好于轮训机制。
项目使用的python版本为3.7, django版本为2.2长期支持版本, chanels为2.4。
前提: 已创建好一个django项目,并创建一个app并且可以成功运行。
博主项目结构, 如图所示:
pip install -U channels
, -U
参数是升级 原来已经安装的包,如果有新版本,不带U不会装新版,带上才会更新到最新版本。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'
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/' , 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()
`
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'
, 通过外部赋值,回调函数变可拿到外部的内容。
其他详细内容可以参考官方文档。