python开发长链接链条式开发纪要

16 阅读1分钟

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下面的页面

image.png

初始化 router.js, 实现两个页面的跳转

image.png

main.js 中引入路由router

image.png

app.vue中整合router,就可以展示路由组件

image.png

main.js 中整合element-plus和样式

image.png

main.js 中引入socket,后期会封装成socket.js 来使用,这样写组件中就可以使用$socket来使用了

image.png

1.3 登录的后端实现

整个后端项目需要跨域:socketio = SocketIO(app, cors_allowed_origins="*")

整合头像组件,当前文件所在的路径



1.3 网站头像解决方案

zlkt.net/post/detail…

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.commit("SETUSER",user);store.commit("SET_USER", user); 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下面

image.png

我机器部署的目录:/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