flask-socketio實(shí)現(xiàn)前后端實(shí)時(shí)通信的功能的示例
一、需求
準(zhǔn)備實(shí)現(xiàn)一個(gè)前后端實(shí)時(shí)發(fā)送消息的功能,即后端發(fā)送一條消息,前端就可以接收到該消息并顯示在頁面上。
二、解決方法
利用Flask-SocketIO實(shí)現(xiàn),F(xiàn)lask-SocketIO使Flask應(yīng)用程序能夠訪問客戶端和服務(wù)器之間的低延遲雙向通信。能夠很好的解決我們的問題
三、具體實(shí)現(xiàn)
步驟一:安裝
pip install eventlet pip install flask-socketio
注意:flask-socketio對版本要求比較嚴(yán)格,如果報(bào)錯(cuò),請更換如下包的版本:
Flask 1.1.4 Flask-SocketIO 4.3.1 python-engineio 3.13.2 python-socketio 4.6.0
步驟二:服務(wù)器代碼
import time
from flask import Flask, request, render_template
from flask_socketio import SocketIO
from threading import Lock
thread = None
thread_lock = Lock()
app = Flask(__name__)
socketio = SocketIO()
socketio.init_app(app, cors_allowed_origins='*') # 用socketio初始化flask的app
flag1 = 0
flag2 = 0
flag3 = 0
@app.route('/', methods=['POST', 'GET'])
def index():
global flag1
global flag2
global flag3
if request.method == 'POST':
# 模擬執(zhí)行你的業(yè)務(wù)邏輯一
time.sleep(5)
# 利用全局變量表明業(yè)務(wù)邏輯一已完成
flag1 = 1
print("步驟1完成")
# 模擬執(zhí)行你的業(yè)務(wù)邏輯二
time.sleep(2)
# 利用全局變量表明業(yè)務(wù)邏輯二已完成
flag2 = 1
print("步驟2完成")
# 模擬執(zhí)行你的業(yè)務(wù)邏輯三
time.sleep(3)
# 利用全局變量表明業(yè)務(wù)邏輯三已完成
flag3 = 1
print("步驟3完成")
return render_template('t1.html')
@socketio.on('connect', namespace='/test_conn')
def test_connect():
"""
此函數(shù)在建立socket連接時(shí)被調(diào)用
"""
print("socket 建立連接")
global thread
with thread_lock:
print(thread)
if thread is None:
# 如果socket連接,則開啟一個(gè)線程,專門給前端發(fā)送消息
thread = socketio.start_background_task(target=background_thread)
@socketio.on('disconnect', namespace='/test_conn')
def disconnect_msg():
"""
此函數(shù)在socket斷開時(shí)被調(diào)用
"""
print('client disconnected!')
def background_thread():
"""
該線程專門用來給前端發(fā)送消息
:return:
"""
global flag1
global flag2
global flag3
while True:
if flag1 == 1:
print("進(jìn)入判斷一")
socketio.emit('server_response',
{'data': '步驟一已完成'}, namespace='/test_conn')
flag1 = 2
socketio.sleep(2)
if flag2 == 1 and flag1 == 2:
print("進(jìn)入判斷二")
socketio.emit('server_response',
{'data': '步驟二已完成'}, namespace='/test_conn')
flag2 = 2
socketio.sleep(2)
if flag3 == 1 and flag2 == 2 and flag1 == 2:
print("進(jìn)入判斷三")
socketio.emit('server_response',
{'data': '步驟三已完成'}, namespace='/test_conn')
flag3 = 2
socketio.sleep(2)
if __name__ == '__main__':
socketio.run(app, host='127.0.0.1', port=5000, debug=True)
步驟三:前端代碼
前端代碼是用vue+element ui編寫。(代碼中所涉及的js文件可以在百度上自行下載,有很多)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="stylesheet" href="static/css/index.css" rel="external nofollow" > <!-- 引入element的css文件-->
<script src="static/js/vue.js"></script> <!-- 引入vue文件-->
<script src="static/js/index.js"></script> <!-- 引入element的js文件-->
<script src="static/js/axios.min.js"></script> <!--引入axios文件-->
<script type="text/javascript" src="static/js/jquery-1.4.2.min.js"></script> <!--引入jquery文件-->
<script type="text/javascript" src="static/js/socket.io.min.js"></script> <!--引入socket文件-->
</head>
<body>
<div id="test">
<el-button type="primary" size="small" @click="onSubmit()">提交</el-button>
<div id = "t"></div>
</div>
</body>
<script>
// 新建vue環(huán)境
new Vue({
el: '#test',
data() {return{} },
methods: {
onSubmit() {
// 向后端發(fā)送post請求
axios.post('http://127.0.0.1:5000/');
// 建立socket連接,此時(shí)會(huì)觸發(fā)后端的@socketio.on('connect', namespace='/test_conn')路由,執(zhí)行test_connect函數(shù)
let socket = io.connect('http://127.0.0.1:5000/test_conn');
socket.on('server_response', function (res) {
//接收到后端發(fā)送過來的消息
var t = res.data;
console.log(t)
if (t) {
// 顯示在頁面上
$("#t").append(t).append('<br/>');
}
});
}
}
})
</script>
</html>結(jié)果展示
啟動(dòng)flask項(xiàng)目,并訪問:

點(diǎn)擊提交后,前端發(fā)送post請求給后端,并建立socket連接:

同時(shí)執(zhí)行index()函數(shù):

同時(shí)前端頁面接收到后端發(fā)送的消息:

至此,前后端交互功能完成!
四、注意事項(xiàng)
1、我們不能直接在socket連接函數(shù)中寫一個(gè)while循環(huán)去發(fā)送信息,例如這樣:
@socketio.on('connect', namespace='/test_conn')
def test_connect():
while True:
socketio.sleep(5)
t = random.randint(1, 100)
socketio.emit('server_response',
{'data': t},namespace='/test_conn')
雖然這樣寫,emit函數(shù)每次都會(huì)執(zhí)行,理論上客戶端應(yīng)該可以定時(shí)收到服務(wù)端的隨機(jī)數(shù)。但是結(jié)果是客戶端根本接收不到,連soketio.on函數(shù)都沒有觸發(fā)運(yùn)行。
原因應(yīng)該是當(dāng)服務(wù)端陷入死循環(huán),會(huì)影響與客戶端之間的websocket連接,總之寫while true需謹(jǐn)慎。
所以,在flask_socketio的示例程序中,我們 用后臺線程 進(jìn)行while循環(huán)以解決這個(gè)問題。
2、websocket連接的一個(gè)典型應(yīng)用是實(shí)現(xiàn)一個(gè)網(wǎng)絡(luò)聊天室,所以就會(huì)有群發(fā)和私聊的功能,我們此處演示的示例,是一個(gè)群發(fā)功能,也就是我們并沒有指定socket的room空間,所以當(dāng)我們從后端發(fā)送給前端消息時(shí),所有打開此頁面的人,都可以看到我們發(fā)送的消息,也就是一個(gè)群發(fā)功能。
到此這篇關(guān)于flask-socketio實(shí)現(xiàn)前后端實(shí)時(shí)通信的功能的示例的文章就介紹到這了,更多相關(guān)flask-socketio實(shí)時(shí)通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python中g(shù)lobal關(guān)鍵字的用法詳解
Python是一種簡單而強(qiáng)大的編程語言,提供了許多功能和語法來幫助開發(fā)人員編寫高效的代碼,其中一個(gè)常用的功能是使用global關(guān)鍵字來在函數(shù)內(nèi)部訪問和修改全局變量,在本文中,我們將深入探討Python中g(shù)lobal關(guān)鍵字的用法,以及使用它的一些最佳實(shí)踐2023-12-12
如何使Python中的print()語句運(yùn)行結(jié)果不換行
這篇文章主要介紹了如何使Python中的print()顯示當(dāng)前語句后不換行,print() 是一個(gè)常用函數(shù),但是每次,print()語句顯示后都會(huì)換行,本問我們就來節(jié)日如何使print()顯示當(dāng)前語句后不換行,需要的朋友可以參考一下2022-03-03
python 實(shí)現(xiàn)圖與圖之間的間距調(diào)整subplots_adjust
這篇文章主要介紹了python 實(shí)現(xiàn)圖與圖之間的間距調(diào)整subplots_adjust,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05
Python?Pandas學(xué)習(xí)之series的二元運(yùn)算詳解
二元運(yùn)算是指由兩個(gè)元素形成第三個(gè)元素的一種規(guī)則,例如數(shù)的加法及乘法;更一般地,由兩個(gè)集合形成第三個(gè)集合的產(chǎn)生方法或構(gòu)成規(guī)則稱為二次運(yùn)算。本文將詳細(xì)講講Pandas中series的二元運(yùn)算,感興趣的可以了解一下2022-09-09
Python實(shí)現(xiàn)將照片變成卡通圖片的方法【基于opencv】
這篇文章主要介紹了Python實(shí)現(xiàn)將照片變成卡通圖片的方法,涉及Python基于opencv庫進(jìn)行圖片處理的相關(guān)操作技巧,需要的朋友可以參考下2018-01-01

