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',所以先放着吧。

socketIO版本搭配

更多内容可以查看

posted @   夏目&贵志  阅读(264)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示