1. 学习纪要
1.1 地址收集
Flask-SocketIO中文文档 zlkt.net/book/detail…
官网地址: socket.io/zh-CN/#
1.2 初始化使用Flask-SocketIO
socketio.run(app)启动项目,route得到:{'data': 'I am connected!'}
from flask import Flask, render_template
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
if __name__ == '__main__':
socketio.run(app)
@socketio.on("connect")
def connect():
print("ip:" + request.remote_addr)
print("sid:" + request.sid)
@socketio.on("my event")
def my_event(data):
print(data)
return {"result": "success"}
index.html 输出:事件发送成功 with result {result: 'success'}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"
integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA=="
crossorigin="anonymous">
</script>
<script type="text/javascript" charset="utf-8">
//自动发起连接
var socket = io();
socket.on('connect', function() {
console.log(socket.connected)
socket.emit('my event', {data: 'I am connected!'}, function (result){
console.log("事件发送成功 with result", result);
});
});
</script>
</body>
</html>
1.3 前端项目的创建
vue create zlqq-client,选择vue3
npm install socket.io-client --save
npm install element-plus --save
npm install vue-router@4.0.12 --save
src 目录下创建编写路由js,router.js
src 目录下创建pages,创建Login.vue, Home.vue, vue.init创建
page下面的页面
初始化 router.js, 实现两个页面的跳转
main.js 中引入路由router
app.vue中整合router,就可以展示路由组件
main.js 中整合element-plus和样式
main.js 中引入socket,后期会封装成socket.js 来使用,这样写组件中就可以使用$socket来使用了
1.3 登录的后端实现
整个后端项目需要跨域:socketio = SocketIO(app, cors_allowed_origins="*")
整合头像组件,当前文件所在的路径
1.3 网站头像解决方案
from flask_avatars import Avatars, Identicon
BASE_DIR = os.path.dirname(__file__)
app.config['AVATARS_SAVE_PATH'] = os.path.join(BASE_DIR, "media", "avatars")
filenames = Identicon().generate(md5(username.encode("utf-8")).hexdigest())
1.4 socket.js 封装
import { io } from "socket.io-client";
class Socket {
constructor() {
if(process.env.NODE_ENV == "production"){
this.server_host = window.location.origin
}else{
this.server_host = "http://127.0.0.1:5000";
}
this.socket = io(this.server_host);
}
connect() {
this.socket.connect();
}
emitLogin(username, callback) {
//emit是发射事件
this.socket.emit("login", { username: username }, (result) => {
if (callback) {
callback(result);
}
});
}
onFriendOnline(callback){
//on是监听事件
this.socket.on("friend online", (result) => {
if(callback){
callback(result)
}
})
}
onFriendOffline(callback){
this.socket.on("friend offline", (result) => {
if(callback){
callback(result)
}
})
}
emitSendMessage(data, callback){
this.socket.emit("send message", {"to": data['to'], "message": data['message']}, (result) => {
if(callback){
callback(result);
}
})
}
onReceiveMessage(callback){
//这个result就是数据
this.socket.on("receive message", (result) => {
if(callback){
callback(result);
}
})
}
get connected() {
return this.socket.connected;
}
}
export default new Socket();
1.5 css 样式
npm install less-loader@7.3.0 --save-dev
npm install less@4.1.2 --save-dev
1.6 vuex的使用
:npm install vuex@4.0.2 --save
建立store.js 文件, export default store;
import store from '@/store'
app.use(store)
import {createStore} from "vuex"
const store = createStore({
state: {
user: null,
// {user, messages, unread}
sessions: [],
current_session: null
},
mutations: {
SET_USER(state, user){
state.user = user
},
ADD_SESSION(state, user){
state.sessions.push({
"user": user,
"messages": [], // {content, date, self}
"unread": 0
})
},
DELETE_SESSION(state, user){
for(let index=0; index<state.sessions.length; index++){
let session = state.sessions[index];
if(session.user.sid == user.sid){
state.sessions.splice(index, 1);
if(state.current_session.user.sid == session.user.sid){
state.current_session = null;
}
break
}
}
},
SET_SESSIONS(state, users){
const sessions = []
for(let user of users){
sessions.push({
"user": user,
"messages": [],
"unread": 0
})
}
state.sessions = sessions;
},
SET_CURRENT_SESSION(state, session){
session.unread = 0;
state.current_session = session;
},
SEND_MESSAGE(state, content){
if(!state.current_session){
return;
}
state.current_session.messages.push({
content: content,
date: (new Date()),
self: true
})
},
RECEIVE_MESSAGE(state, data){
const sid = data['sid']
const content = data['content']
let chat_session = null
for(let session of state.sessions){
if(session.user.sid == sid){
chat_session = session
break
}
}
if(chat_session){
chat_session.messages.push({
content: content,
date: (new Date()),
self: false
})
if(!state.current_session ||
state.current_session.user.sid != chat_session.user.sid
){
chat_session.unread += 1
}
}
}
},
getters: {
logined(state){
return state.user?true:false;
}
}
});
export default store;
组件中vuex的使用 this.store.state.user this.$store.getters.logined
1.7 项目打包部署
pip install eventlet 以后terminal 本地启动: python app.py
本来flask本地启动是每隔5min轮训一次长链接才能感知到连接是断开的,改用eventlet就是立马感知连接断开的
前端项目打包放到python代码中
npm run build
index.html 放到templates文件夹下,其余的放到static下面
我机器部署的目录:/home/hulanpython
tar -czvf hulan-server.tar.gz ./hulan-server
scp hulan-server.tar.gz root@1.117.109.40:/tmp
pip install -r requirements.txt
pip install gunicorn
pip uninstall eventlet
pip install eventlet==0.30.2
gunicorn --worker-class=eventlet --workers=1 --bind=0.0.0.0:5000 app:app