WebSocket
服务端向客户端主动推送消息
1、轮询
不推荐,客户端定时请求服务端数据更新。
缺点:
- 大量消耗服务器内存和宽带资源,不停请求服务器,很多时候并没有新的数据,都是无效请求。
- 数据不一定实时更新,要看设定的请求间隔,会有延迟。
2、长轮询(兼容性好)
也是客户端请求服务端,但是服务端不是即时返回,阻塞有内容更新才返回(或者创建队列)。流程上面看作服务端向客户端推送内容。一般可使用队列Queue实现,阻塞10s。
优点:数据实时更新
缺点:服务器挂起耗内存。
3、webSocket
Socket:是在应用层和传输层之间的一个抽象层,把TCP/IP的复杂操作抽象为简单的接口,供应用层调用实现进程在网络中通信。
WebSocket:是一个基于TCP的网络协议。和HTTP一样属于应用层,让客户端和服务器双向通信的的技术。他可以让客户端和浏览器创建连接之后,不断开,两端可以相互通信。
http/https:他们也是网络协议,一次请求,一次响应,http是明文传输,https是秘文传输,都是无状态的短链接。
3.1、webSocket原理
- 握手环节。验证服务端是否支持websocket协议
1、浏览器随机生成一个字符串发送给服务端
2、服务器接收到随机字符串,将他与magic string拼接,然后再sha1/base64加密,将密闻文返回给浏览器
3、浏览器自动进行校验
- 收发数据。密文
3.2、Django实现webSocket是channels
pip install channels==2.3
pip install django==1.11
建议python3.6环境
在channels里面已经实现了握手、加密、解密等环节。
注意:不是所有服务端都支持webSocket。
- django 默认不支持 需要安装channels
- flask 默认不支持 需要安装geventwebsocket
- tornado 默认支持
步骤
1、settings.py里注册channels
INSTALLED_APPS = ['channels']
2、配置
ASGI_APPLICATION = 'MyBill.routing.application'
3、创建【MyBill/routing.py】
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from app01 import consumers
application = ProtocolTypeRouter({
'websocket': URLRouter([
path('chat/', consumers.chatConsumer)
])
})
4、视图
from channels.exceptions import StopConsumer
from channels.generic.websocket import WebsocketConsumer
class chatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""
握手环节过程中触发
客户端发来连接请求之后
:param message:
:return:
"""
# 服务端接受连接,向客户端发送加密的字符串
self.accept()
def websocket_receive(self, message):
"""
客户端向浏览器发送消息,自动被触发
:param message:
:return:
"""
print('消息内容:', message)
# 服务端回消息
self.send(text_data='收到了')
def websocket_disconnect(self, message):
"""
客户端主动断开链接被触发
:param message:
:return:
"""
# 服务端断开连接
raise StopConsumer()
5、客户端调用websocket
new WebSocket对象
6、多人聊天需要OBJECT_LIST
from channels.exceptions import StopConsumer
from channels.generic.websocket import WebsocketConsumer
OBJECT_LIST = []
class chatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""
握手环节过程中触发
客户端发来连接请求之后
:param message:
:return:
"""
# 服务端接受连接,向客户端发送加密的字符串
self.accept()
OBJECT_LIST.append(self)
def websocket_receive(self, message):
"""
客户端向浏览器发送消息,自动被触发
:param message:
:return:
"""
print('消息内容:', message)
# 服务端回消息
# self.send(text_data='收到了')
for item in OBJECT_LIST:
item.send(text_data=message['text'])
def websocket_disconnect(self, message):
"""
客户端主动断开链接被触发
:param message:
:return:
"""
# 服务端断开连接
OBJECT_LIST.remove(self)
raise StopConsumer()