flask-socket的实践

1.长连接和短连接的由来

1)TCP在真正的读写操作之前,server与client之间必须建立一个连接,

当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,

连接的建立通过三次握手,释放则需要四次握手,

所以说每个连接的建立都是需要资源消耗和时间消耗的。

2)短连接就是我们平时登陆注册,建立的连接

3)长连接主要适用于通信,比如说qq聊天

2.示例代码

server.py
import socket
import threadingBUF_SIZE = 1024
host = 'localhost'
port = 8083def handle_client(client_socket, address):print("Connected by", address)while True:try:data = client_socket.recv(BUF_SIZE)if not data:print("Connection closed by client", address)breakprint(data.decode())except ConnectionResetError:print("Connection reset by client", address)breakclient_socket.close()server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen(5)  # 增加可接收连接数print("Server is listening on port", port)while True:client_socket, address = server.accept()client_handler = threading.Thread(target=handle_client, args=(client_socket, address))client_handler.start()
client.py
import socket
import timehost = 'localhost'
port = 8083client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)  # 开启心跳维护try:client.connect((host, port))print("Connected to server")while True:client.send('hello world\r\n'.encode())print('send data')time.sleep(1)  # 可以设置更长的时间来验证长时间不发送数据的情况
except ConnectionRefusedError:print("Connection failed")
except Exception as e:print("An error occurred:", e)
finally:client.close()

3.flask提供长连接

flask-socket.py
from flask import Flask, render_template
from flask_socketio import SocketIO, sendapp = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)@app.route('/')
def index():return render_template('./index.html')@socketio.on('message')
def handle_message(message):print('Received message: ' + message)send('Message received: ' + message)if __name__ == '__main__':socketio.run(app, debug=True)
html代码
<!DOCTYPE html>
<html><head><title>SocketIO Chat</title><script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script><script type="text/javascript" charset="utf-8">document.addEventListener('DOMContentLoaded', () => {const socket = io();socket.on('connect', () => {console.log('Connected to server');});socket.on('message', (msg) => {console.log('Message from server: ' + msg);});document.querySelector('#send').addEventListener('click', () => {const message = document.querySelector('#message').value;socket.send(message);});});</script></head><body><input id="message" type="text" placeholder="Enter message"><button id="send">Send</button></body>
</html>

4.flask工厂模式修改为socket

1)目录结构
LongChain/
│
├── app/
│   ├── __init__.py
│   ├── main/
│   │   ├── __init__.py
│   │   ├── routes.py
│   ├── socketio.py
├── templates/
│   └── index.html
├── create_app.py
├── requirements.txt
2)/app/__init__.py
from flask import Flask
from .socketio import socketiodef create_app():app = Flask(__name__, template_folder='../templates')app.config['SECRET_KEY'] = 'secret!'# Initialize SocketIO with the appsocketio.init_app(app)# Import and register blueprintsfrom .main import main as main_blueprintapp.register_blueprint(main_blueprint)print(app.template_folder)  # 打印模板文件夹路径return app3)app/socketio.py
from flask_socketio import SocketIOsocketio = SocketIO()@socketio.on('message')
def handle_message(message):print('Received message: ' + message)socketio.send('Message received: ' + message)
4)app/main/__init__.py
from flask import Blueprintmain = Blueprint('main', __name__)from . import routes
5)app/main/routes.py
from flask import render_template
from . import main@main.route('/')
def index():return render_template('./index.html')
6)templates/index.html
<!DOCTYPE html>
<html><head><title>SocketIO Chat</title><script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script><script type="text/javascript" charset="utf-8">document.addEventListener('DOMContentLoaded', () => {const socket = io();socket.on('connect', () => {console.log('Connected to server');});socket.on('message', (msg) => {console.log('Message from server: ' + msg);});document.querySelector('#send').addEventListener('click', () => {const message = document.querySelector('#message').value;socket.send(message);});});</script></head><body><input id="message" type="text" placeholder="Enter message"><button id="send">Send</button></body>
</html>
7)create_app.py
from app import create_app
from app.socketio import socketioapp = create_app()if __name__ == "__main__":socketio.run(app, debug=True, host='0.0.0.0')

5.项目代码更改

首先要在app文件夹下建一个extensions.py文件,是为了解决在run.py和init.py里面循环引入socket的问题

1)__init__.py修改
# app/__init__.py
from flask import Flask, render_template, request, g, jsonify, redirect, url_for, session
from app.user.views import user_bp
from app.blog.views import blog_bp
from app.comment.views import comment_bp
from app.drunk1.views import drunk1_bp
from app.onedrunk1.views import onedrunk1_bp
from app.extensions import socketio
import sqlite3
import time
import tracebackdef create_app():app = Flask(__name__, static_url_path='/static')# 加载配置app.config.from_object('config.Config')socketio.init_app(app)# 注册蓝图app.register_blueprint(user_bp, url_prefix='/conversation')app.register_blueprint(blog_bp, url_prefix='/userprofile')app.register_blueprint(comment_bp, url_prefix='/drunk5')app.register_blueprint(drunk1_bp, url_prefix='/drunk1')app.register_blueprint(onedrunk1_bp, url_prefix='/onedrunk1')DATABASE = r'C:\Users\lzt\Desktop\work\flask\app\static\users2.db'# session密钥app.secret_key = 'Cxh12300'current_user = {}def get_db():db = getattr(g, '_database', None)if db is None:db = g._database = sqlite3.connect(DATABASE)return db@app.teardown_appcontextdef close_connection(exception):db = getattr(g, '_database', None)if db is not None:db.close()@app.route('/')def login():return render_template('./login/login.html')@app.route('/regist')def regist():return render_template('./regist/regist.html')@app.route('/registuser', methods=['POST'])def getRigistRequest():try:if request.method == 'POST':username = request.form.get('user')password = request.form.get('password')conn = get_db()cursor = conn.cursor()sql = "INSERT INTO user(user, password) VALUES (?, ?)"cursor.execute(sql, (username, password))conn.commit()return redirect(url_for('login'))else:return render_template('login.html')except Exception as e:traceback.print_exc()return '注册失败'@app.route('/login', methods=['POST'])def getLoginRequest():try:username = request.form.get('user')password = request.form.get('password')conn = get_db()cursor = conn.cursor()sql = "SELECT * FROM user WHERE user=? AND password=?"cursor.execute(sql, (username, password))user = cursor.fetchone()if user:name = user[0]user_id = user[2]current_user['name'] = user[0]current_user['user_id'] = user[2]session['name'] = user[0]session['user_id'] = user[2]current_time = time.time()expiration_time = current_time + 10payload = {'name': name, 'user_id': user_id, 'exp': expiration_time}return render_template('./user/index2qian.html', name=name, user_id=user_id)else:return '用户名或密码不正确'except Exception as e:traceback.print_exc()return '登录失败'return app
2)run.py
from app import create_app, socketioapp = create_app()if __name__ == "__main__":socketio.run(app, debug=True, host='0.0.0.0')
3)app/user/views.py的修改
from flask import Blueprint, render_template,request,jsonify,session
import sqlite3
import traceback
import time
import requests
import json
from flask_socketio import emit
from app.extensions import socketio
user_bp = Blueprint('user', __name__, template_folder='templates')@user_bp.route('/')
def index():return render_template('./user/index2qian.html')
def generate_user_profile(session):# 基本 URLbase_url = "http://192.168.1.140:5000/userprofile/generate_user_profile"# 从 session 中获取 user_id 和 nameprint("session111",session)user_id = session['user_id']name = session['name']print("user_id",user_id)# 构建完整的 URLurl = f"{base_url}?user_id={user_id}&name={name}"try:# 发送 GET 请求response = requests.get(url)# 检查响应状态码if response.status_code == 200:# 成功print("Profile generated successfully")return response.json()else:# 请求失败print(f"Failed to generate profile, status code: {response.status_code}")return Noneexcept Exception as e:print(f"An error occurred: {e}")return None
def get_latest_content_by_user_id(session):# 数据库文件名db_file = r'C:\Users\lzt\Desktop\work\flask\app\static\conversions2.db'# 连接到 SQLite 数据库conn = sqlite3.connect(db_file)cursor = conn.cursor()try:# SQL 查询语句,按 id 降序排列并只获取最新的一条记录query = '''SELECT content FROM profileWHERE user_id = ?ORDER BY id DESCLIMIT 1'''# 执行查询cursor.execute(query, (session['user_id'],))# 获取结果result = cursor.fetchone()if result:content = result[0]  # 获取 content 字段的值return contentelse:return Noneexcept sqlite3.Error as e:print(f"An error occurred: {e}")return Nonefinally:# 关闭数据库连接conn.close()@socketio.on('message')
def handle_message(data):user_input = data['message']conversation_history = data['history']response = ChatBot.call_api(user_input, conversation_history)# print("user_input",user_input)# print("conversation_history",conversation_history)# print("触发emit")# print("response",response)emit('response', {'response': response})class ChatBot:context = Noneconversation_counter = 0@classmethoddef call_api(cls, user_input, conversation_history):# 每十轮对话更新一次 profileprint("cls.conversation_counter:", cls.conversation_counter)if cls.conversation_counter % 10 == 0:print("更新 profile,因为对话计数是 10 的倍数")generate_user_profile(session)profile = get_latest_content_by_user_id(session)if profile:profile_prompt = f"根据你的行为分析,你的兴趣和喜好如下:{profile}\n"print("Profile 更新成功:", profile)else:profile_prompt = ""print("Profile 更新失败或没有新的 profile 数据")else:profile_prompt = ""# 更新对话计数器cls.conversation_counter += 1# API URLurl = 'http://192.168.1.108:11434/api/chat'# 定义基本 promptprompt = ("你只会中文。你只能说中文。""你的性格积极乐观,善良可爱,喜欢和朋友聊天,善解人意。但你不会直说自己的性格。""你喜欢提出问题,并继续聊下去一两句。当你感觉到用户的回答很敷衍的时候,你会找新话题。""你的每句回应要尽可能像真正的朋友。你的回答不可以敷衍。""<人物画像>的意思是对人物行为分析,从而能够区别其喜好等特点.""你对有关用户的<人物画像>的问题都很好奇。如果说了一些性格特征,你会追问一两次,然后开启新的话题。""但你是个情商很高的人,你会说很多种句式的话。你会用中文表达的很完美。""禁止直接提‘人物画像’的字眼。你可以问有关性格爱好的问题,但不能明说<人物画像>一词。""每次说话不多余30个单词。\n")# 将 profile 添加到 prompt 中prompt = profile_prompt + prompt# print("最终 prompt:", prompt)data = {"model": "llama3","messages": conversation_history + [{"role": "user","content": prompt + user_input}],"context": cls.context,"stream": False}headers = {'Content-Type': 'application/json'}data=data_clean(data)# print(type(data))# print('data',data)try:response = requests.post(url, data=json.dumps(data), headers=headers)print("API 请求已发送")# print("json.dumps(data)",json.dumps(data))if response.status_code == 200:response_json = response.json()print("API 响应成功:", response_json)messages = response_json.get('message', {})content = messages.get('content')cls.context = response_json.get('context')return contentelse:print(f'请求失败,状态码: {response.status_code}')print('响应内容:', response.content)return Noneexcept Exception as e:print(f'发生错误: {e}')traceback.print_exc()return None
def data_clean(data):try:messages = data['messages']conversations = []for item in messages:if 'role' in item and 'content' in item:role = "user" if item['role'] == 'user' else "system"content = item['content']conversations.append({'role': role, 'content': content})else:role = item['sender']content = item['message']if role != 'AI':role = 'user'else:role = 'system'conversations.append({'role': role, 'content': content})data['messages']=conversationsreturn dataexcept Exception as e:print(f"数据处理错误: {e}")return None
@user_bp.route('/chat', methods=['POST'])
def chat():data=request.get_data()print("data",data)# user_input=data['message']data_str = data.decode('utf-8')# 将字符串解析为字典data_dict = json.loads(data_str)print("data_dict",data_dict)# 获取 "message" 键对应的值messages = data_dict["message"]userInput=data_dict['userInput']conversations = []for item in messages:role = item["sender"]content = item["message"]if role != "AI":role = "user"else:role = "system"conversations.append({'role': role, 'content': content})response=ChatBot.call_api(userInput,conversations)return jsonify({"response": response})@user_bp.route('/save-message', methods=['POST'])
def save_message():data = request.get_json()print("save_message  data",data)conn = sqlite3.connect('C:\\Users\\lzt\\Desktop\\work\\flask\\app\\static\\conversions2.db')cursor = conn.cursor()for msg in data:message = msg.get('message')timestamp = msg.get('timestamp')sender = msg.get('sender')user_id = msg.get('user_id')  # 获取用户的 user_id# 插入数据到数据库,包括 user_idcursor.execute('''INSERT INTO conversation (timestamp, sender, message, user_id) VALUES (?, ?, ?, ?)''', (timestamp, sender, message, user_id))# 提交更改conn.commit()conn.close()return jsonify({'message': 'Messages saved to database successfully.'})4)前端的修改
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Chat with AI</title><link rel="stylesheet" href="../static/styles.css">
</head>
<body><h1 style="text-align: center;">Chat with AI</h1><div id="chat-container"><div class="message ai-message">AI: Hello there! How can I assist you today?</div></div><div id="userProfile"></div><div id="input-container"><input type="text" id="user-input" placeholder="Your message..." onkeypress="handleKeyPress(event)"><button id="send-button" class="button" onclick="sendMessage()">Send</button><button id="save-button" class="button" onclick="fetchUserProfile()">生成我的用户画像</button><button id="drunk1" class="button" onclick="redirectToDrunk1()">one  drunk</button><button id="onedrunk1" class="button" onclick="redirectToDrunk2()">two drunk</button></div>
</body>
</html>
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
<script>function redirectToDrunk1() {var url = "http://192.168.1.140:5000/onedrunk1?user_id=" + encodeURIComponent(userid) + "&name=" + encodeURIComponent(name);window.location.href = url;}function redirectToDrunk2() {window.location.href = "http://192.168.1.140:5000/drunk1";}// 全局变量,记录已经保存到数据库的消息数量var savedMessageCount = 0;var userid = "{{ user_id }}"; // 从服务器端获取的用户IDvar name="{{name}}"console.log("name",name,"userid",userid)function parseMessages() {var chatContainer = document.getElementById('chat-container');var messages = [];chatContainer.querySelectorAll('.message').forEach(message => {messages.push(message.textContent);});console.log("messages",messages)var now = new Date();var year = now.getFullYear();var month = now.getMonth() + 1;var day = now.getDate();var hours = now.getHours();var minutes = now.getMinutes();var formattedTime = year + "-" + month + "-" + day + " " + hours + ":" + minutes;var result = [];if (messages.length >= 20) {messages = messages.slice(-15);}for (var i = 0; i < messages.length; i++) {var message = messages[i];var sender = "";const regex = /([^:]+)/;const messageType = regex.exec(message);if (messageType[0] === "AI") {sender = "AI";} else{sender = userid;}if (sender !== "") {var messageContent = message.substring(message.indexOf(":") + 1);var messageObject = {"timestamp": formattedTime,"sender": sender,"message": messageContent};result.push(messageObject);}}console.log("functionresult",result)return result;
}function isTokenExpired(token) {if (!token) {return true; // 如果没有token,认为已过期}// 从JWT中解析出exp字段,判断是否小于当前时间戳const exp = jwt_decode(token).exp;return exp < Date.now() / 1000;}// 检查JWT是否过期,如果过期则重新登录function checkAndRefreshToken() {const jwt = localStorage.getItem('jwt');if (isTokenExpired(jwt)) {// JWT已过期,重新登录window.location.href = '/login'; // 重定向到登录页面}}function saveToDatabase(message) {// 调用函数检查并刷新JWT// checkAndRefreshToken();// 遍历数据,为每个对象添加"user_id"message.forEach(function(msg) {msg["user_id"] = userid;});// console.log("data", message);var jwt = localStorage.getItem('jwt');// 发送 POST 请求到后端接口fetch('/conversation/save-message', {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': 'Bearer ' + jwt},body: JSON.stringify(message) // 将消息数据转换为 JSON 字符串并作为请求体发送}).then(response => response.json()).then(data => {// 在控制台打印后端返回的响应数据// console.log(data);//  fetchUserProfile();}).catch(error => {// 发生错误时打印错误信息console.error('Error:', error);});}var socket = io.connect('http://' + document.domain + ':' + location.port);socket.on('connect', function() {console.log('Connected to server');
});
socket.on('response', function(data) {var aiMessageDiv = document.createElement('div');aiMessageDiv.classList.add('message', 'ai-message');aiMessageDiv.textContent = 'AI: ' + data.response;console.log("data.response",data.response)document.getElementById('chat-container').appendChild(aiMessageDiv);var chatContainer = document.getElementById('chat-container');var messages = [];chatContainer.querySelectorAll('.message').forEach(message => {messages.push(message.textContent);});var now = new Date();var year = now.getFullYear();var month = now.getMonth() + 1;var day = now.getDate();var hours = now.getHours();var minutes = now.getMinutes();var formattedTime = year + "-" + month + "-" + day + " " + hours + ":" + minutes;var result = [];for (var i = savedMessageCount; i < messages.length; i++) {var message = messages[i];var sender = "";const regex = /([^:]+)/; // 匹配 ":" 之前的任意字符(不包括 ":"),并且只提取匹配到的内容const messageType = regex.exec(message);console.log("messageType[0] ", messageType[0] )if (messageType[0] === "AI") {sender = "AI";} else {sender = userid;}// console.log("sender",sender)if (sender !== "") {var messageContent = message.substring(message.indexOf(":") + 1);// console.log("messageContent",messageContent)var messageObject = {"timestamp": formattedTime,"sender": sender,"message": messageContent};// console.log("messageObject",messageObject)result.push(messageObject);}}savedMessageCount = messages.length;console.log("result", result);saveToDatabase(result);});async function sendMessage() {var userInput = document.getElementById('user-input').value.trim();if (userInput === '') {return;}var chatContainer = document.getElementById('chat-container');var userMessageDiv = document.createElement('div');userMessageDiv.classList.add('message', 'user-message');userMessageDiv.textContent = name +':'+ userInput;chatContainer.appendChild(userMessageDiv);newValue=parseMessages();socket.emit('message', {message: userInput,history: newValue});document.getElementById('user-input').value = '';}function handleKeyPress(event) {if (event.key === 'Enter' && !event.shiftKey) { // 检查是否按下了 Enter 键且未按下 Shift 键event.preventDefault(); // 阻止默认的 Enter 键行为(即提交表单)sendMessage(); // 调用 sendMessage 函数发送消息} else if (event.key === 'Enter' && event.shiftKey) { // 如果同时按下了 Shift 键和 Enter 键var input = document.getElementById('user-input');var start = input.selectionStart;var end = input.selectionEnd;var value = input.value;input.value = value.substring(0, start) + '\n' + value.substring(end);input.selectionStart = input.selectionEnd = start + 1; // 将光标移动到换行符后}}function saveConversation() {var chatContainer = document.getElementById('chat-container');var messages = [];// 遍历聊天容器中的所有消息,并将其保存到数组中chatContainer.querySelectorAll('.message').forEach(message => {messages.push(message.textContent);});var now = new Date();var year = now.getFullYear(); // 获取年份var month = now.getMonth() + 1; // 获取月份(注意要加1,因为月份是从0开始的)var day = now.getDate(); // 获取日期var hours = now.getHours(); // 获取小时var minutes = now.getMinutes(); // 获取分钟var formattedTime = year + "-" + month + "-" + day + " " + hours + ":" + minutes;var result = [];for (var i = 0; i < messages.length; i++) {var message = messages[i];var sender = "";var messageType = message.substring(0, 4);// 根据消息类型确定发送者if (messageType === "AI: ") {sender = "AI";} else if (messageType === "User") {sender = userid;}// 构造消息对象并添加到结果数组中if (sender !== "") {var messageContent = message.substring(message.indexOf(":") + 2); // 获取冒号后面的消息内容// console.log(messageContent)var messageObject = {"timestamp": formattedTime,"sender": sender,"message": messageContent};result.push(messageObject);}}}function fetchUserProfile() {
fetch( 'http://192.168.1.140:5000/userprofile/generate_user_profile?user_id=' + userid + '&name=' + name, {method: 'GET',headers: {'Content-Type': 'application/json',},
})
.then(response => {if (!response.ok) {throw new Error('Network response was not ok');}return response.text(); // 直接获取文本内容
})
.then(data => {console.log("response.data", data);// 这里可以对返回的文本内容进行处理,例如将其显示在页面上const userProfileDiv = document.getElementById('userProfile');userProfileDiv.innerText = data;
})
.catch(error => {console.error('Error:', error);
});
}</script>

主要就是前端点击发送按钮触发

            socket.emit('message', {

                message: userInput,

                history: newValue

            });

然后后端接受前端传的消息并且调用对应的方法传参,再将结果传给前端

@socketio.on('message')

def handle_message(data):

    user_input = data['message']

    conversation_history = data['history']

    response = ChatBot.call_api(user_input, conversation_history)

    # print("user_input",user_input)

    # print("conversation_history",conversation_history)

    # print("触发emit")

    # print("response",response)

    emit('response', {'response': response})

前端收到返回的信息socket.on('response', function(data) {)
进行下一步的处理

  • 后端:

    • 监听客户端连接、断开连接和消息事件。
    • 接收到消息后,将其广播给所有连接的客户端。
  • 前端:

    • 监听服务器广播的消息事件,并在页面上显示消息。
    • 监听表单提交事件,发送用户输入的消息到服务器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/364897.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java基于ssm+jsp 二手车交易网站

1用户功能模块 定金支付管理&#xff0c;在定金支付管理页面可以填写订单编号、车型、品牌、分类、车身颜色、售价、订金金额、付款日期、备注、用户名、姓名、联系方式、是否支付等信息&#xff0c;进行详情、修改&#xff0c;如图1所示。 图1定金支付管理界面图 预约到店管…

“论大数据处理架构及其应用”写作框架,软考高级,系统架构设计师

论文真题 大数据处理架构是专门用于处理和分析巨量复杂数据集的软件架构。它通常包括数据收集、存储、处理、分析和可视化等多个层面&#xff0c;旨在从海量、多样化的数据中提取有价值的信息。Lambda架构是大数据平台里最成熟、最稳定的架构&#xff0c;它是一种将批处理和流…

kicad第三方插件安装问题

在使用KICAD时想安装扩展内容&#xff0c;但是遇到下载失败&#xff0c;因为SSL connect error。 因为是公司网络&#xff0c;我也不是很懂&#xff0c;只能另寻他法。找到如下方法可以曲线救国。 第三方插件包目录 打开存放第三方插件存放目录&#xff0c;用于存放下载插件包…

通俗范畴论4 范畴的定义

注:由于CSDN无法显示本文章源文件的公式,因此部分下标、字母花体、箭头表示可能会不正常,请读者谅解 范畴的正式定义 上一节我们在没有引入范畴这个数学概念的情况下,直接体验了一个“苹果1”范畴,建立了一个对范畴的直观。本节我们正式学习范畴的定义和基本性质。 一个…

【WPF】Windows系统桌面应用程序编程开发新手入门-打造自己的小工具

电脑Windows系统上的桌面程序通常是用Visual Studio 开发工具编写出来的&#xff0c;有两种开发方式供选择&#xff0c;一种是WindowForm&#xff0c;简称WinForm&#xff0c;另一种是Windows Presentation Foundation&#xff0c;简称WPF&#xff0c;这里将学习WPF项目。 文章…

收银系统源码-千呼新零售【全场景收银】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

云计算-期末复习题-框架设计/选择/填空/简答(2)

目录 框架设计 1.负载分布架构 2.动态可扩展架构 3.弹性资源容量架构 4.服务负载均衡架构 5.云爆发结构 6.弹性磁盘供给结构 7.负载均衡的虚拟服务器实例架构 填空题/简答题 单选题 多选题 云计算期末复习部分练习题&#xff0c;包括最后的部分框架设计大题(只是部分…

C++ | Leetcode C++题解之第200题岛屿数量

题目&#xff1a; 题解&#xff1a; class Solution { private:void dfs(vector<vector<char>>& grid, int r, int c) {int nr grid.size();int nc grid[0].size();grid[r][c] 0;if (r - 1 > 0 && grid[r-1][c] 1) dfs(grid, r - 1, c);if (r …

基于HarmonyOS NEXT开发智能提醒助手

目录 目录 目录 前言 关于HarmonyOS NEXT 智能提醒助手需求分析 智能提醒助手设计 1、系统架构 2、功能模块 智能提醒助手的应用场景 智能提醒助手的竞争力 具体技术实现 未来展望 结束语 前言 随着智能设备的普及和物联网技术的飞速发展&#xff0c;人们对于智能…

云计算 | 期末梳理(下)

1.模运算 2. 拓展欧几里得算法 3.扩散和混淆、攻击的分类 香农的贡献:定义了理论安全性,提出扩散和混淆原则,奠定了密码学的理论基础。扩散:将每一位明文尽可能地散布到多个输出密文中去,以更隐蔽明文数字的统计特性。混淆:使密文的统计特性与明文密钥之间的关系尽量复杂…

混合专家模型(MoE)的前世今生

在文章《聊聊最近很火的混合专家模型&#xff08;MoE&#xff09;》中&#xff0c;我们简单介绍了MoE模型的定义和设计&#xff0c;并且比较了MoE和Dense模型的区别&#xff0c;今天我们继续来回顾一下MoE模型发展的历史和最新的发展现状。 从去年GPT-4发布至今&#xff0c;MoE…

初阶数据结构之堆讲解

本篇文章带大家学习的是堆&#xff0c;还请各位观众老爷给个三连 正片开始 堆的概念 如果有一个关键码的集合 K { &#xff0c; &#xff0c; &#xff0c; … &#xff0c; } &#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中&#xff0c;并满…

查看Windows启动时长

&#xff08;附图片&#xff09;电脑自带检测开机时长---查看方式_电脑开机时长命令-CSDN博客 eventvwr - Windows日志 - 系统 - 查找 - 6013.jpg

SpringBoot(一)创建一个简单的SpringBoot工程

Spring框架常用注解简单介绍 SpringMVC常用注解简单介绍 SpringBoot&#xff08;一&#xff09;创建一个简单的SpringBoot工程 SpringBoot&#xff08;二&#xff09;SpringBoot多环境配置 SpringBoot&#xff08;三&#xff09;SpringBoot整合MyBatis SpringBoot&#xff08;四…

VMware中的三种虚拟网络模式

虚拟机网络模式 1 主机网络环境2 VMware中的三种虚拟网络模式2.1 桥接模式NAT模式仅主机模式网络模式选择1 VMware虚拟网络配置2 虚拟机选择网络模式3 Windows主机网络配置 配置静态IP 虚拟机联网方式为桥接模式&#xff0c;这种模式下&#xff0c;虚拟机通过主机的物理网卡&am…

半个月从几十升粉到500(发红包喽)

目录 1. 背景2. 涨粉秘籍2.1 持续创作高质量内容2.1.1 保持频率2.1.2 技术文章为主2.1.3 图文并茂 2.2 积极参与社区活动2.2.1 社区分享2.2.2 发文活动 2.3 互动与建立信任2.3.1 与读者互动2.3.2 红包互动2.3.3 动态分享 2.4 标题与内容的优化2.4.1 标题吸引2.4.2 内容实用 2.5…

吴恩达机器学习 第三课 week2 推荐算法(上)

目录 01 学习目标 02 推荐算法 2.1 定义 2.2 应用 2.3 算法 03 协同过滤推荐算法 04 电影推荐系统 4.1 问题描述 4.2 算法实现 05 总结 01 学习目标 &#xff08;1&#xff09;了解推荐算法 &#xff08;2&#xff09;掌握协同过滤推荐算法&#xff08;Collabo…

【大数据导论】大数据序言

各位大佬好 &#xff0c;这里是阿川的博客&#xff0c;祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 目录 数据概念及类型及可用及组织形式数据概念数据…

HarmonyOS应用开发学习经验

一、HarmonyOS学习官网 开发者能力认证 HarmonyOS应用开发者基础认证6月之前的学习资源官网已经关闭过期&#xff0c;大家不要慌&#xff0c;官方更新了最新资源&#xff0c;但是&#xff0c;对于之前没有学习完的学员不友好&#xff0c;存在知识断片的现象&#xff0c;建议官…

ctfshow sqli-libs web541--web551

web541 and和or 被替换为空格 # 还有 1 也是不能生效的?id-1 union select 1,2,3-- 双写绕过 ?id-1 union select 1,(select group_concat(table_name) from infoorrmation_schema.tables where table_schemactfshow),3 -- flags?id-1 union select 1,(select group_con…