python|WebSocket在Python中的应用


文章目录

  • 前言
  • Socket.IO
  • Flask Sockets
  • 参考

前言 WebSocket与HTTPS相似,是一种客户端-服务端模型的通信协议。
HTTP carries extra overheard in individual request and response, WebSocket carries the overhead data while placing connection then it carries less or balanced data within individual request-response.
HTTP WebSocket
Added overhead due to SSL handshake and likewise carries added overhead in individual request-response Lessor moderate overhead while establishing the connection and less overhead in individual requests
The client needs to interact with the server via a specific method for communication or transmission of data WebSocket is bi-directional
Half-Duplex Full-Duplex
Service push is not supported natively, client pulling or download streaming is required The Service push is base of WebSocket implementation
Socket.IO socket.io是一个基于WebSocket的CS的实时通信库,它底层基于engine.io。engine.io使用WebSocket和xhr-polling(或jsonp)封装了一套自己的协议,在不支持WebSocket的低版本浏览器中来代替。socket.io在engine.io的基础上增加了namespace,room,自动重连等特性。
在HTTP 协议开发的时候,并不是为了双向通信程序准备的,起初的 web 应用程序只需要 “请求-响应” 就够了。由于历史原因,在创建拥有双向通信机制的 web 应用程序时,就只能利用 HTTP 轮询的方式,由此产生了 “短轮询” 和 “长轮询”(注意区分短连接和长连接)。
短轮询通过客户端定期轮询来询问服务端是否有新的信息产生,缺点也是显而易见,轮询间隔大了则信息不够实时,轮询间隔过小又会消耗过多的流量,增加服务器的负担。长轮询是对短轮询的优化,需要服务端做相应的修改来支持。客户端向服务端发送请求时,如果此时服务端没有新的信息产生,并不立刻返回,而是Hang住一段时间等有新的信息或者超时再返回,客户端收到服务器的应答后继续轮询。可以看到长轮询比短轮询可以减少大量无用的请求,并且客户端接收取新消息也会实时不少。
虽然长轮询比短轮询优化了不少,但是每次请求还是都要带上HTTP请求头部,而且在长轮询的连接结束之后,服务器端积累的新消息要等到下次客户端连接时才能传递。更好的方式是只用一个TCP连接来实现客户端和服务端的双向通信,WebSocket协议正是为此而生。WebSocket是基于TCP的一个独立的协议,它与HTTP协议的唯一关系就是它的握手请求可以作为一个Upgrade request经由HTTP服务器解析,且与HTTP使用一样的端口。WebSocket默认对普通请求使用80端口,协议为ws://,对TLS加密请求使用443端口,协议为wss://
更多详细内容可以查看参考[2]。
Flask Sockets 【python|WebSocket在Python中的应用】接下来我们使用Flask-SocketIO来创建一个Socketio的Demo。具体文档可以参考:Flask-SocketIO,代码可以参考:Web Socket。
  1. 创建环境
    使用conda命令创建一个新的环境,然后安装如下依赖:
Flask==1.0.2 Flask-Login==0.4.1 Flask-Session==0.3.1 Flask_SocketIO itsdangerous==1.1.0 Jinja2==2.10 MarkupSafe==1.1.0 python-engineio python-socketio six==1.11.0 Werkzeug==0.14.1

  1. 创建应用
创建app.py
from flask import Flask, render_template from flask_socketio import SocketIO async_mode = None app = Flask(__name__) socket_ = SocketIO(app, async_mode=async_mode) @app.route('/') def index(): return render_template('index.html', sync_mode=socket_.async_mode)if __name__ == '__main__': socket_.run(app, debug=True)

创建前端测试页面index.html
WebSocket - 锐客网 This is webSocket client

  1. 运行app.py
    运行app.py后在浏览器中访问:http://localhost:5000/ ,成功的话会在前端页面上有提示信息:This is WebSocket Client。具体的工程目录如下:
    python|WebSocket在Python中的应用
    文章图片
最终的app.pyindex.html代码如下:
from flask import Flask, render_template, session, copy_current_request_context from flask_socketio import SocketIO, emit, disconnect from threading import Lockasync_mode = None app = Flask(__name__) app.config['SECRET_KEY'] = 'secret!' socket_ = SocketIO(app, async_mode=async_mode) thread = None thread_lock = Lock()@app.route('/') def index(): return render_template('index.html', async_mode=socket_.async_mode)@socket_.on('my_event', namespace='/test') def test_message(message): session['receive_count'] = session.get('receive_count', 0) + 1 emit('my_response', {'data': message['data'], 'count': session['receive_count']})@socket_.on('my_broadcast_event', namespace='/test') def test_broadcast_message(message): session['receive_count'] = session.get('receive_count', 0) + 1 emit('my_response', {'data': message['data'], 'count': session['receive_count']}, broadcast=True)@socket_.on('disconnect_request', namespace='/test') def disconnect_request(): @copy_current_request_context def can_disconnect(): disconnect()session['receive_count'] = session.get('receive_count', 0) + 1 emit('my_response', {'data': 'Disconnected!', 'count': session['receive_count']}, callback=can_disconnect)if __name__ == '__main__': socket_.run(app, debug=True)

Socket-Test - 锐客网 src="https://www.it610.com//code.jquery.com/jquery-1.12.4.min.js"> src="https://www.it610.com//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"> type="text/javascript" charset="utf-8"> $(document).ready(function() {namespace = '/test'; var socket = io(namespace); socket.on('connect', function() { socket.emit('my_event', {data: 'connected to the SocketServer...'}); }); socket.on('my_response', function(msg, cb) { $('#log').append('
' + $('').text('logs #' + msg.count + ': ' + msg.data).html()); if (cb) cb(); }); $('form#emit').submit(function(event) { socket.emit('my_event', {data: $('#emit_data').val()}); return false; }); $('form#broadcast').submit(function(event) { socket.emit('my_broadcast_event', {data: $('#broadcast_data').val()}); return false; }); $('form#disconnect').submit(function(event) { socket.emit('disconnect_request'); return false; }); }); Socket
Logs

参考
  1. Implement a WebSocket Using Flask and Socket-IO(Python)
  2. Socket.io原理分析

    推荐阅读