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()

3.3、channels-layers 主流的群发