websocket的简单了解和python应用
序
web时代,http协议是当之无愧的幸运儿,它是在TCP传输层协议的基础上,建立的web应用层协议,主要进行html文本的传输,其他的都能算是http当中元素的渲染。早期只是简单的html文本,后续引入css优化了样式,美化了显示,然后的js又加强了动态渲染,而后后续的种种web框架在提升程序员开发效率的同时,也进行各种安全和性能上的优化。但有一点不变的是,http服务端只能被动地去接收来自客户端的请求,在经历后台处理以后,再做出响应。
针对这种被动的单向请求,当服务器存在信息变更的时候,想要主动推送信息给客户就非常麻烦。为此而生的技术,有js种的自动请求,在构建网页的时候,就事先做好了js设定,在一定情况下或者时间内,组织客户端技术发起请求;但这种技术能用,但不够美观,效率也没有跟上预期,在设计上更理想的就是,服务器在信息进行变更的情况下,马上推送更新后信息给客户端,而websocket就应了这种需求而诞生。
实现
websocket是单个TCP连接上全双工通信,在客户端和服务端进行一次握手后,就可以实现持续连接,从而进行数据的双向传输。在客户端或者服务端任意一方发起建立websocket通信的请求以后,对端进行确认式回应,然后一个类似tcp的连接建立,因此常用于IM通信的情景。
websocket和http相同的地方,都是基于TCP的可靠性传输的应用层协议;不同的是websocket是双向的,http是单向的,而且websocket通信前,需要发起一个握手连接,而客户端在http请求发起前,服务端并不知道对端存在。
实现原理:在websocket通信前,通信是http形式,而两者都是基于TCP连接的,所以websocket连接的握手,客户端就是在TCP连接建立以后,在http头中放进去特定的信息,如下:
GET /chat HTTP/1.1
Host: www.example.com
Upgrade: websocket
Connection: Upgrade
上面表示客户端准备升级连接为长连接的websocket,而服务器的成功回应是这样的:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
响应成功以后,tcp连接就这么长久维持,双方传输的信息大多是json格式的文本信息。因为是基于TCP的通信,所以它的各种特点都是和tcp相仿的。
websocket在flask中的应用
flask是一个轻量级的web框架,它本身可以提供简单的web api,但如果想要更多的功能,就需要自己去寻找插件的支持了,也是因为这些丰富的插件,才使得flask应用广泛。websocket在flask中的应用,就是flask-sockets和flask_socketIO,前者是对websocket的简单实现,对于已经实现了websocket支持的浏览器友好,丑拒旧版不支持websocket的浏览器;后者的功能是前者的丰富和补全,因为它支持旧版,能做到这点,就已经很足够了。
flask_sockets使用
进行试验以前,当然要进行经典的pip:
pip install flask
pip install flask-cors
pip install flask-sockets
示例如下:
from flask import Flask, render_template
from flask_sockets import Sockets
from flask_cors import *
from time import sleep
app = Flask(__name__)
socket = Sockets(app)
CORS(app, supports_credentials=True)
# 返回一个内含websocket请求发起js的html
@app.route('/')
def home():
return render_template('index.html')
@socket.route('/hello')
def hello(ws):
print('websocket处理')
while not ws.closed():
ws.send("你大爷")
sleep(3)
if __name__ == '__main__':
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('',8090), app, handler_class=WebSocketHandler)
print('服务开启监听')
server.serve_forever()
主要是给一个主页面,使其返回一个内含链接的html页面,它内含js,在点击跳转的时候可以进行websocket的请求构造:
<!DOCTYPE html>
<html>
<body>
<div align="center">
<h1>Welcome,My Friend.</h1>
<a href="javascript:enter()">来进入下一个领域吧</a>
</div>
</body>
<script>
function enter(){
if ('WebSocket' in window){
// 创建websocket即发起请求
var web_socket = new WebSocket("ws://localhost:8090/hello")
// 设置onmessage事件的回调,也就是接收数据
web_socket.onmessage = function(event){
console.log(event.data)
}
// 设置onopen的回调
web_socket.onopen = function(){
console.log("开始连接")
}
// 设置onclose的回调
web_socket.onclose = function(event) {
console.log('连接结束:'+event.code)
}
} else {
alert('浏览器不支持websocket')
}
}
</script>
</html>
当然,设置一个带有点击事件的button也不是不可以。
...
<button onclick="enter(this)">来进入下一个领域吧</button>
...
去前台f12一下,可以看到hello请求的请求头:

和响应:

flask-socketIO使用
使用前同样需要安装一下:
pip install flask
pip install flask-socketIO
实例:
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'test'
socketIo = SocketIO()
# 添加cors支持,解决跨域问题
socketIo.init_app(app, cors_allowed_origin='*')
name_space = '/hello'
@app.route('/')
def home():
return render_template('index.html')
@app.route('/push')
def push_msg():
event_name = 'hello'
broadcasted_data = {'data':'test'}
# 广播信息
socketIo.emit(event_name, broadcasted_data, broadcast=False, namespace=name_space)
return 'over'
# 设置websocket连接建立后回调
@socketIo.on('connect', namespace=name_space)
def connect():
print(f'websocket连接已建立,namespace:{name_space}')
# 设置websocket连接断开后回调
@socketIo.on('disconnect', namespace=name_space)
def disconnect():
print(f'websocket连接已断开,namespace:{name_space}')
@socketIo.on('event1', namespace=name_space)
def test(msg):
print(f'客户端:{msg}')
emit('response', {'data':msg['data'], 'count':1})
if __name__ == '__main__':
# 不像往常的app.run,这里不显示运行所在
socketIo.run(app,host='0.0.0.0', port=8090)
在js中,使用jquery也可以构建websocekt通信,下面有一个加载ajax的例子,就是在加载了html以后,它的js自动请求后续内容,进行渲染:
<script>
$(document).ready(function () {
namespace = '/hello';
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);
socket.on('hello', function (res) {
var data_show = res.data;
if (data_show) {
$("#data_show").append(data_show).append('<br/>');
}
});
});
</script>
但在实践的时候,却问题百出,一个是没有引入js库
<header>
<script src="https://lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
</header>
一个是python的flask-socketIO、python-socketIO和python-engineIO版本不搭,使用下面图片对标的版本进行安装,后面又有其他问题ImportError: cannot import name 'run_with_reloader' from 'werkzeug.serving',所以先放着吧。


浙公网安备 33010602011771号