首页 技术随笔

1. websocket

1.1 websocket是什么

  • WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议
  • WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
  • 在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
  • Websocket的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

我们可以看一下http和websocket的连接过程

websocket.png

1.2 websocket技术发展

  1. AJAX轮询
  2. Long Polling长轮询

我们都知道,不使用WebSocket与服务器实时交互,一般有两种方法。AJAX轮询和Long Polling长轮询。

AJAX轮询

AJAX轮询也就是定时发送请求 (每隔n秒发送request给服务器,询问现在有没有数据更新),也就是普通的客户端与服务端通信过程,只不过是无限循环发送,这样,可以保证服务端一旦有最新消息,就可以被客户端获取。
ws.png

Long Polling长轮询

Long Polling长轮询是客户端和浏览器保持一个长连接,等服务端有消息返回,断开。
然后再重新连接,也是个循环的过程,无穷尽也。。。

客户端发起一个Long Polling,服务端如果没有数据要返回的话,
会hold住请求,等到有数据,就会返回给客户端。客户端又会再次发起一次Long Polling,再重复一次上面的过程。

  • 这个有点像我一直盯着服务器,只要服务器有空,我就要和你建立长连接

缺点

上边这两种方式都有个致命的弱点,开销太大,被动性。假设并发很高的话,这对服务端是个考验。
而WebSocket一次握手,持久连接,以及主动推送的特点可以解决上边的问题,又不至于损耗性能。

1.3 websocket优点

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

2. Flask-SocketIO

Flask-SocketIO是python的一个库,通过这个库可以使用python进行websocket通信

Flask-SocketIO开发文档

首先需要知道,Flask的websocket通信也是需要WSGI的,在使用flask进行websocket的时候,需要认识到这三种WSGI

Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)

  1. eventlet
  2. gevent
  3. Werkzeug

2.1 eventlet

eventlet是性能最好的选项,并支持长轮询和WebSocket传输。

2.2 gevent

许多不同的配置都支持gevent。gevent软件包完全支持长轮询传输,但是与eventlet不同,gevent不具有本机WebSocket支持。要增加对WebSocket的支持,目前有两个选择。安装gevent-websocket 软件包可以为gevent添加WebSocket支持,或者可以使用带有WebSocket功能的uWSGI Web服务器。gevent的使用也是一种性能选择,但比eventlet略低。

2.3 Werkzeug

也可以使用基于Werkzeug的Flask开发服务器,但要注意的是,它缺乏其他两个选项的性能,因此只能用于简化开发工作流程。此选项仅支持长轮询传输。

很显然,要使用websocket通信应该选择eventlet作为WSGI服务器

3.安装 eventlet

pip install eventlet

安装完之后再安装flask-socketio

pip install flask-socketio

安装flask-socketio后,我们需要知道flask-socketio的版本号,因为使用websocket的过程中,肯定是有服务器端和客户端

两端都要运行websocket,一般前端都是使用javascript进行websocket通信的,并且由于flask-socketio是基于websocket深度封装的,所以在前端需要导入一个js文件,前后端的包版本号一定那个要严格按表中的匹配,否则通信失败
2021-01-09_22-40.png

4. websocket通信基础

flask使用ws需要进一步封装

我们首先要对一般的flask框架进行再封装
过程
首先导入SocketIO

from flask_socketio import SocketIO

导入后,再对app进行初始化

socketio = SocketIO(app,cors_allowed_origins='*')
# cors_allowed_origins='*' 允许跨源请求

然后将app.run替换成socketio.run

if __name__ == '__main__':
    #app.run()
    socketio.run(app,host='0.0.0.0',port=5000,debug=True)
# socketio进一步封装

这样基本就完成websocket的封装了

ws的基本知识

使用websocket一般称之为会话,也就是首先客户端打开浏览器通过js脚本会话主动连接到服务器

5. websocket通信实例

客户端

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
       <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.5/socket.io.js"></script>
</head>
<body>
<div id="t">
</div>
<script type="text/javascript">
    $(document).ready(function () {
        var url = location.href;
        var socket = io.connect(url);
        socket.on('test',function (res){
            {#alert(res);#}
            var t = res;
            if (t){
                $('#t').append(t).append('<br>');
            }
        })
        
    })
</script>

</body>
</html>

服务器

from flask import render_template
from flask_socketio import SocketIO,emit
app = Flask(__name__)
app.secret_key = '905008'  #session 密钥
# app.debug = True
socketio = SocketIO(app,cors_allowed_origins='*')
@socketio.on('test')
def test123():
    print('hello world')

@app.route("/test")
@app.route("/test",methods=["POST","GET"])
def test():
    return render_template("user/test.html")

@app.route('/push')
def push():
    event_name = 'test'
    broadcast_data = "hello world!"
    emit(event_name,broadcast_data,broadcast=True,namespace=name_space)
    return "done!"

if __name__ == '__main__':
    # app.run()
    socketio.run(app,host='0.0.0.0',port=5000,debug=True)



文章评论

目录