WebSocket主從服務器架構完整教程

目錄

1. 前言:為什么要學習WebSocket主從架構

第一章:基礎知識準備

2.1 什么是WebSocket

生活中的例子

技術特點

2.2 WebSocket vs HTTP

什么時候用WebSocket?

2.3 什么是主從架構

生活中的例子

技術架構圖

2.4 環境準備

需要的軟件

項目結構

第二章:WebSocket基礎入門

3.1 第一個WebSocket服務器

3.2 第一個WebSocket客戶端

3.3 消息通信基礎

消息格式設計

常見消息類型

完整的消息處理示例

第三章:主從架構設計原理

4.1 架構設計思路

為什么需要主從架構?

架構演進過程

4.2 核心組件說明

1. 主服務器(Master Server)

2. 從服務器(Slave Server)

3. 客戶端(Client)

4.3 通信協議設計

通信流程詳解

消息協議規范

第四章:主服務器詳細實現

5.1 主服務器架構

核心類設計

5.2 從服務器管理

從服務器信息結構

從服務器注冊流程

5.3 負載均衡實現

多種負載均衡策略

5.4 完整代碼實現

第五章:從服務器詳細實現

6.1 從服務器架構

核心類設計

6.2 與主服務器通信

連接管理

6.3 客戶端管理

客戶端連接處理

6.4 完整代碼實現

第六章:客戶端詳細實現

7.1 客戶端連接流程

連接流程圖

7.2 自動重連機制

重連策略


1. 前言:為什么要學習WebSocket主從架構

想象一下,你正在開發一個實時在線游戲,有成千上萬的玩家同時在線。如果只用一臺服務器,會發生什么?

  • 服務器壓力巨大,可能隨時崩潰
  • 玩家體驗差,延遲高
  • 無法擴展,玩家數量受限

這就是為什么我們需要學習WebSocket主從架構!它能幫助我們:

  1. 分散壓力:把玩家分配到不同的服務器
  2. 提高性能:每個服務器只處理部分玩家
  3. 易于擴展:需要時隨時增加服務器
  4. 高可用性:一臺服務器掛了,其他的繼續工作

本教程將帶你從零開始,一步步掌握這個強大的架構!


第一章:基礎知識準備

2.1 什么是WebSocket

生活中的例子

想象兩種通信方式:

  1. 寫信(HTTP)

    • 你寫一封信(請求)
    • 寄給朋友
    • 等待回信(響應)
    • 想再說話?再寫一封信
  2. 打電話(WebSocket)

    • 撥通電話(建立連接)
    • 隨時可以說話(發送消息)
    • 對方也能隨時回話(接收消息)
    • 直到掛斷電話(斷開連接)

WebSocket就像打電話,一旦連接建立,雙方可以隨時通信!

技術特點
// HTTP方式(傳統)
客戶端: "服務器,現在幾點?"
服務器: "下午3點"
// 連接斷開客戶端: "服務器,現在幾點?" // 需要重新連接
服務器: "下午3點01分"
// 連接又斷開// WebSocket方式
客戶端 <--持續連接--> 服務器
客戶端: "現在幾點?"
服務器: "下午3點"
客戶端: "天氣如何?"
服務器: "晴天"
服務器: "對了,有新消息!" // 服務器主動推送
// 連接一直保持

2.2 WebSocket vs HTTP

特性HTTPWebSocket
通信方式請求-響應全雙工
連接狀態短連接長連接
服務器推送不支持支持
實時性低(需要輪詢)
資源消耗高(頻繁建立連接)低(保持連接)
適用場景普通網頁實時應用
什么時候用WebSocket?

? 適合使用WebSocket的場景

  • 在線聊天
  • 實時游戲
  • 股票行情
  • 協同編輯
  • 直播彈幕
  • IoT實時數據

? 不適合使用WebSocket的場景

  • 靜態網頁
  • RESTful API
  • 文件下載
  • 表單提交

2.3 什么是主從架構

生活中的例子

想象一個大型餐廳的廚房:

     總廚師長(主服務器)|分配任務和協調|+-----+-----+-----+|     |     |     |廚師1 廚師2 廚師3 廚師4(從服務器)|     |     |     |菜品1 菜品2 菜品3 菜品4(處理客戶請求)
  • 總廚師長:不做菜,只負責分配訂單給各個廚師
  • 廚師們:實際做菜,每個廚師負責一部分訂單
  • 優勢:效率高,一個廚師累了還有其他的

這就是主從架構的核心思想!

技術架構圖
                    ┌─────────────────┐│   主服務器       ││   (Master)      ││                 ││ · 管理從服務器   ││ · 分配客戶端     ││ · 負載均衡       ││ · 健康檢查       │└────────┬────────┘│┌────────────────────┼────────────────────┐│                    │                    │┌────▼─────┐        ┌────▼─────┐        ┌────▼─────┐│從服務器1  │        │從服務器2  │        │從服務器3  ││(Slave 1) │        │(Slave 2) │        │(Slave 3) ││          │        │          │        │          ││·處理業務  │        │·處理業務  │        │·處理業務  ││·管理客戶端│        │·管理客戶端│        │·管理客戶端│└────┬─────┘        └────┬─────┘        └────┬─────┘│                    │                    │客戶端1,2,3          客戶端4,5,6          客戶端7,8,9

2.4 環境準備

需要的軟件
  1. Node.js(版本 14.0 以上)

    # 檢查是否安裝
    node --version# 如果沒有安裝,去官網下載:https://nodejs.org
    
  2. 代碼編輯器(推薦 VS Code)

    • 下載地址:https://code.visualstudio.com
  3. 創建項目目錄

    # 創建項目文件夾
    mkdir websocket-master-slave
    cd websocket-master-slave# 初始化項目
    npm init -y# 安裝依賴
    npm install ws
    
項目結構
websocket-master-slave/
├── package.json          # 項目配置文件
├── master-server.js      # 主服務器
├── slave-server.js       # 從服務器
├── client.js            # 客戶端
├── config/              # 配置文件夾
│   ├── master.json      # 主服務器配置
│   └── slave.json       # 從服務器配置
├── logs/                # 日志文件夾
├── test/                # 測試文件夾
└── README.md            # 項目說明

第二章:WebSocket基礎入門

在深入主從架構之前,我們先來掌握WebSocket的基礎知識。

3.1 第一個WebSocket服務器

讓我們從最簡單的WebSocket服務器開始:

// simple-server.js
const WebSocket = require('ws');// 創建WebSocket服務器,監聽8080端口
const wss = new WebSocket.Server({ port: 8080 });console.log('WebSocket服務器啟動在端口 8080');// 當有客戶端連接時
wss.on('connection', function connection(ws) {console.log('新客戶端連接了!');// 向客戶端發送歡迎消息ws.send('歡迎連接到WebSocket服務器!');// 當收到客戶端消息時ws.on('message', function incoming(message) {console.log('收到消息:', message.toString());// 回復客戶端ws.send(`服務器收到了你的消息: ${message}`);});// 當客戶端斷開連接時ws.on('close', function close() {console.log('客戶端斷開連接');});// 錯誤處理ws.on('error', function error(err) {console.error('WebSocket錯誤:', err);});
});// 每5秒向所有連接的客戶端發送時間
setInterval(() => {wss.clients.forEach((client) => {if (client.readyState === WebSocket.OPEN) {client.send(`當前時間: ${new Date().toLocaleTimeString()}`);}});
}, 5000);

代碼解釋

  1. new WebSocket.Server({ port: 8080 }) - 創建服務器
  2. wss.on('connection', ...) - 監聽新連接
  3. ws.on('message', ...) - 監聽消息
  4. ws.send(...) - 發送消息
  5. wss.clients - 所有連接的客戶端

3.2 第一個WebSocket客戶端

// simple-client.js
const WebSocket = require('ws');// 連接到服務器
const ws = new WebSocket('ws://localhost:8080');// 連接成功時
ws.on('open', function open() {console.log('成功連接到服務器!');// 發送消息給服務器ws.send('你好,服務器!');// 每3秒發送一次消息setInterval(() => {if (ws.readyState === WebSocket.OPEN) {ws.send(`客戶端時間: ${new Date().toLocaleTimeString()}`);}}, 3000);
});// 收到服務器消息時
ws.on('message', function incoming(data) {console.log('收到服務器消息:', data.toString());
});// 連接關閉時
ws.on('close', function close() {console.log('與服務器斷開連接');
});// 錯誤處理
ws.on('error', function error(err) {console.error('連接錯誤:', err);
});// 處理進程退出
process.on('SIGINT', () => {console.log('\n正在關閉連接...');ws.close();process.exit();
});

3.3 消息通信基礎

消息格式設計

在實際應用中,我們通常使用JSON格式傳遞消息:

// 消息格式示例
const message = {type: 'chat',        // 消息類型data: {              // 消息數據user: '張三',text: '大家好!',time: Date.now()}
};// 發送時轉換為字符串
ws.send(JSON.stringify(message));// 接收時解析JSON
ws.on('message', (data) => {const message = JSON.parse(data);console.log(`${message.data.user}: ${message.data.text}`);
});
常見消息類型
// 定義消息類型常量
const MessageTypes = {// 系統消息CONNECT: 'connect',           // 連接DISCONNECT: 'disconnect',     // 斷開HEARTBEAT: 'heartbeat',       // 心跳ERROR: 'error',              // 錯誤// 業務消息CHAT: 'chat',                // 聊天JOIN_ROOM: 'join_room',      // 加入房間LEAVE_ROOM: 'leave_room',    // 離開房間USER_LIST: 'user_list',      // 用戶列表// 主從通信REGISTER: 'register',         // 注冊SYNC: 'sync',                // 同步BROADCAST: 'broadcast'       // 廣播
};
完整的消息處理示例
// message-handler.js
class MessageHandler {constructor(ws) {this.ws = ws;this.handlers = new Map();this.registerHandlers();}// 注冊消息處理器registerHandlers() {this.handlers.set('chat', this.handleChat.bind(this));this.handlers.set('join_room', this.handleJoinRoom.bind(this));this.handlers.set('heartbeat', this.handleHeartbeat.bind(this));}// 處理收到的消息handleMessage(data) {try {const message = JSON.parse(data);const handler = this.handlers.get(message.type);if (handler) {handler(message.data);} else {console.log('未知消息類型:', message.type);}} catch (error) {console.error('消息解析錯誤:', error);}}// 處理聊天消息handleChat(data) {console.log(`[聊天] ${data.user}: ${data.text}`);// 廣播給其他用戶this.broadcast({type: 'chat',data: data});}// 處理加入房間handleJoinRoom(data) {console.log(`${data.user} 加入了房間 ${data.room}`);// 處理加入房間的邏輯}// 處理心跳handleHeartbeat(data) {// 回復心跳this.send({type: 'heartbeat',data: { timestamp: Date.now() }});}// 發送消息send(message) {if (this.ws.readyState === WebSocket.OPEN) {this.ws.send(JSON.stringify(message));}}// 廣播消息(需要訪問所有客戶端)broadcast(message) {// 這里需要服務器支持}
}

第三章:主從架構設計原理

4.1 架構設計思路

為什么需要主從架構?

讓我們通過一個故事來理解:

小明開了一家網絡游戲公司,最初只有100個玩家,一臺服務器輕松應對。隨著游戲火爆,玩家增長到10000人,服務器開始卡頓。小明買了更好的服務器,但玩家繼續增長到100000人,再好的單臺服務器也扛不住了。

這時,小明想到:為什么不用多臺服務器分擔壓力呢?

這就是主從架構的起源!

架構演進過程
  1. 單服務器階段

    所有客戶端 --> 單一服務器優點:簡單
    缺點:性能瓶頸、單點故障
    
  2. 簡單集群階段

    客戶端 --> 負載均衡器 --> 多個獨立服務器優點:負載分散
    缺點:服務器間無法通信
    
  3. 主從架構階段

    客戶端 --> 從服務器 <--> 主服務器 <--> 從服務器 <-- 客戶端優點:負載分散、統一管理、服務器間可通信
    缺點:架構復雜度增加
    

4.2 核心組件說明

1. 主服務器(Master Server)

職責

  • ?? 從服務器的注冊和管理
  • ?? 負載均衡(決定客戶端連接哪個從服務器)
  • ?? 健康檢查(監控從服務器狀態)
  • ?? 消息路由(跨服務器消息轉發)
  • ?? 全局狀態管理

類比:就像交通指揮中心,不直接運送乘客,但協調所有公交車的調度。

2. 從服務器(Slave Server)

職責

  • ?? 處理客戶端連接
  • ?? 執行具體業務邏輯
  • ?? 向主服務器報告狀態
  • ?? 與其他從服務器同步數據

類比:就像具體的公交車,實際運送乘客,并向調度中心報告位置。

3. 客戶端(Client)

職責

  • ?? 向主服務器請求分配
  • ?? 連接到指定的從服務器
  • ?? 執行應用功能

類比:就像乘客,先問調度中心該上哪輛車,然后上車。

4.3 通信協議設計

通信流程詳解
1. 從服務器啟動并注冊Slave --> Master: {type: "register", name: "slave-1", capacity: 100}Master --> Slave: {type: "register_success", slaveId: "s1"}2. 心跳保活Slave --> Master: {type: "heartbeat", slaveId: "s1"}Master --> Slave: {type: "heartbeat_ack"}3. 客戶端請求分配Client --> Master: {type: "request_server"}Master --> Client: {type: "server_assigned", host: "192.168.1.2", port: 8081}4. 客戶端連接從服務器Client --> Slave: {type: "connect", userId: "u123"}Slave --> Client: {type: "connect_success"}5. 跨服務器消息Slave1 --> Master: {type: "forward", target: "slave2", data: {...}}Master --> Slave2: {type: "forwarded", from: "slave1", data: {...}}
消息協議規范
// 基礎消息結構
{id: "唯一消息ID",type: "消息類型",timestamp: "時間戳",data: {// 具體數據}
}// 主從通信消息類型
const MasterSlaveProtocol = {// 從服務器 -> 主服務器SLAVE_REGISTER: 'slave:register',        // 注冊SLAVE_HEARTBEAT: 'slave:heartbeat',      // 心跳SLAVE_STATUS: 'slave:status',            // 狀態報告SLAVE_SYNC: 'slave:sync',                // 數據同步// 主服務器 -> 從服務器MASTER_REGISTER_ACK: 'master:register_ack',   // 注冊確認MASTER_HEARTBEAT_ACK: 'master:heartbeat_ack', // 心跳確認MASTER_COMMAND: 'master:command',             // 命令下發MASTER_BROADCAST: 'master:broadcast',         // 廣播消息// 客戶端 -> 主服務器CLIENT_REQUEST: 'client:request',        // 請求分配// 主服務器 -> 客戶端MASTER_ASSIGN: 'master:assign',          // 分配服務器MASTER_REJECT: 'master:reject'           // 拒絕請求
};

第四章:主服務器詳細實現

5.1 主服務器架構

主服務器是整個系統的大腦,讓我們詳細實現它的每個功能。

核心類設計
// master-server-core.js
class MasterServer {constructor(config) {// 配置this.config = {port: config.port || 8080,heartbeatInterval: config.heartbeatInterval || 10000,heartbeatTimeout: config.heartbeatTimeout || 30000,...config};// 核心數據結構this.slaves = new Map();        // 從服務器集合this.clients = new Map();       // 客戶端分配記錄this.stats = {                  // 統計信息totalConnections: 0,totalMessages: 0,startTime: Date.now()};// 狀態this.slaveIdCounter = 0;        // 從服務器ID計數器this.isRunning = false;         // 運行狀態}
}

5.2 從服務器管理

從服務器信息結構
class SlaveInfo {constructor(ws, registerData) {this.id = null;                      // 由主服務器分配this.ws = ws;                        // WebSocket連接this.name = registerData.name;       // 從服務器名稱this.host = registerData.host;       // 主機地址this.port = registerData.port;       // 端口號this.capacity = registerData.capacity || 100;  // 容量this.currentLoad = 0;                // 當前負載this.status = 'active';              // 狀態this.lastHeartbeat = Date.now();     // 最后心跳時間this.metadata = registerData.metadata || {};   // 額外信息this.performance = {                 // 性能指標cpu: 0,memory: 0,responseTime: 0};}// 獲取負載率getLoadRate() {return this.currentLoad / this.capacity;}// 是否可用isAvailable() {return this.status === 'active' && this.getLoadRate() < 0.9;}// 更新心跳updateHeartbeat() {this.lastHeartbeat = Date.now();}// 轉換為客戶端可見信息toClientInfo() {return {id: this.id,host: this.host,port: this.port,name: this.name};}
}
從服務器注冊流程
// 在 MasterServer 類中
registerSlave(ws, data) {// 驗證注冊信息if (!this.validateSlaveData(data)) {this.sendToWebSocket(ws, {type: 'register_error',error: '注冊信息不完整'});return;}// 檢查是否重復注冊const existingSlave = this.findSlaveByHostPort(data.host, data.port);if (existingSlave) {console.log(`從服務器 ${data.name} 重新連接`);// 更新現有連接existingSlave.ws = ws;existingSlave.status = 'active';existingSlave.updateHeartbeat();ws.slaveId = existingSlave.id;this.sendToWebSocket(ws, {type: 'register_success',slaveId: existingSlave.id,message: '重新連接成功'});return;}// 創建新的從服務器記錄const slaveInfo = new SlaveInfo(ws, data);slaveInfo.id = ++this.slaveIdCounter;// 保存到集合this.slaves.set(slaveInfo.id, slaveInfo);ws.slaveId = slaveInfo.id;// 發送注冊成功消息this.sendToWebSocket(ws, {type: 'register_success',slaveId: slaveInfo.id,config: {heartbeatInterval: this.config.heartbeatInterval}});console.log(`? 從服務器 ${slaveInfo.name} (ID: ${slaveInfo.id}) 注冊成功`);// 通知其他從服務器this.broadcastToSlaves({type: 'slave_joined',slave: slaveInfo.toClientInfo()}, slaveInfo.id);// 觸發事件this.emit('slave:registered', slaveInfo);
}// 驗證從服務器數據
validateSlaveData(data) {return data.name && data.host && data.port;
}// 根據主機和端口查找從服務器
findSlaveByHostPort(host, port) {for (const slave of this.slaves.values()) {if (slave.host === host && slave.port === port) {return slave;}}return null;
}

5.3 負載均衡實現

多種負載均衡策略
// load-balancer.js
class LoadBalancer {constructor() {this.strategies = new Map();this.currentStrategy = 'least_connections';this.roundRobinIndex = 0;// 注冊所有策略this.registerStrategies();}registerStrategies() {

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88623.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88623.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88623.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java的extends通配符

在Java泛型中&#xff0c;extends通配符用于限定泛型類型的上界&#xff0c;即指定泛型可以是某個類型或其子類型。它有兩種常見用法&#xff1a;類型參數限定和通配符限定&#xff0c;下面詳細介紹&#xff1a; 1. 類型參數限定&#xff08;在類/方法定義中&#xff09; 在定義…

vue自定義提示框組件

不想要elementui的消息提示&#xff0c;自定義一個組件系統統一使用 一、寫頁面 vue &#xff08;我放的目錄是src/plugins/message.vue&#xff09;&#xff08;這里面使用elementui 里面icon 需要單獨引入&#xff09; <template><Transition name"down"&…

自動駕駛數據集綜述:統計特征、標注質量與未來展望

自動駕駛數據集綜述&#xff1a;統計特征、標注質量與未來展望 A Survey on Autonomous Driving Datasets: Statistics, Annotation Quality, and a Future Outlook 得益于硬件和深度學習技術的快速進步&#xff0c;自動駕駛近年來迅速發展并展現出良好的性能。高質量的數據集…

redis數據結構和數據類型

1.動態字符串SIMPLE DYNAMIC STRING(SDS)觀察上圖中的SDS結構&#xff0c;頭部包含字符串長度和分配的空間&#xff0c;可以以O&#xff08;1&#xff09;的時間復雜度計算出字符串長度&#xff0c;并且有了字符串長度后可以無視c語言的字符串缺陷&#xff08;\0作為結尾標識&a…

深度學習--神經網絡

一、深度學習的簡單概念深度學習是一種模仿人類大腦的運行方式&#xff0c;從大量數據中學習特征的學習模式。深度學習是機器學習的子集&#xff0c;它與機器學習的關系如下&#xff1a;二、感知神經網絡2.1簡單定義神經網絡&#xff08;Neural Networks&#xff09;是一種模擬…

.NET 程序的強名稱簽名與安全防護技術干貨

在 .NET 開發領域&#xff0c;保障程序的安全性和完整性至關重要。強名稱簽名和有效的安全防護措施是實現這一目標的關鍵手段。下面將詳細介紹 .NET 程序的強名稱簽名以及相關的安全防護方法。一、什么是強名稱簽名強名稱簽名是 .NET 框架提供的一種安全機制&#xff0c;其主要…

DNS(Domain Name System,域名系統)

目錄 **一、DNS的核心功能****二、DNS的工作原理****1. 解析流程(以車載導航請求為例)****2. 關鍵機制****三、車載以太網中DNS的特殊性**1. **高可靠性要求**2. **低延遲優化**3. **安全挑戰與防護****四、DNS相關協議與技術****五、車載DNS配置示例****六、DNS故障排查工具…

優化 ECharts 多條折線:折線數據不完整導致的X軸日期錯亂問題

目錄 一、簡單介紹 1.1 常見類型 二、時間軸錯亂問題 2.1 示例 2.2 示例完整代碼 2.3 問題分析 2.4 修復方法 第一步 第二步 2.5 優化后完整代碼 一、簡單介紹 ECharts 是一款基于 JavaScript 的數據可視化圖表庫&#xff0c;動態圖表是 ECharts 的一個重要應用場景…

網絡安全之注入攻擊:原理、危害與防御之道

網絡安全之注入攻擊&#xff1a;原理、危害與防御之道 引言 在OWASP Top 10安全風險榜單中&#xff0c;注入攻擊常年占據首位。2023年Verizon數據泄露調查報告顯示&#xff0c;67%的Web應用漏洞與注入類攻擊直接相關。本文從技術視角系統解析注入攻擊的核心原理、典型場景及防御…

Python爬蟲動態IP代理報錯全解析:從問題定位到實戰優化

目錄 一、代理IP失效&#xff1a;爬蟲的"隱形殺手" 1.1 失效場景復現 1.2 解決方案 二、403封禁&#xff1a;反爬機制的"精準打擊" 2.1 封禁原理剖析 2.2 破解方案 三、速度瓶頸&#xff1a;代理性能的"致命短板" 3.1 性能對比測試 3.2…

機器學習基礎知識【 激活函數、損失函數、優化器、 正則化、調度器、指標函數】

目錄標題機器學習基礎知識概覽激活函數 (Activation Functions)損失函數 (Loss Functions / Cost Functions)優化器 (Optimizers)正則化 (Regularization)調度器 (Schedulers / Learning Rate Schedulers)指標函數 (Metric Functions)其他重要概念訓練流程機器學習基礎知識概覽…

【達夢數據庫|JPA】后端數據庫國產化遷移記錄

項目背景 經典的springbootjpa&#xff0c;java1.8數據庫MySQL需要遷移到國產化數據庫達夢上 開發環境安裝 最簡單的方式&#xff1a; 官方網站下載安裝時選擇“典型安裝”即可 Linux安裝 國產化一律上docer不要猶豫 下載三方提供的docker鏡像按頁面文檔啟動即可同上下載官…

ubuntu22默認安裝firefox使用snap安裝還老打不開解決辦法

終極解決方案&#xff08;100% 避免 Snap 版 Firefox&#xff09; 步驟 1&#xff1a;徹底移除 Snap 版 Firefox bash sudo snap remove --purge firefox 步驟 2&#xff1a;添加 Mozilla 官方 PPA&#xff08;提供 .deb 版 Firefox&#xff09; bash sudo add-apt-repository …

MyBatis02-mybatis-config.xml配置文件講解

mybatis-config.xml 是 MyBatis 的核心配置文件&#xff0c;用于配置整個 MyBatis 框架的全局行為&#xff0c;比如環境&#xff08;數據源&#xff09;、事務、類型別名、插件、Mapper 映射等。示例&#xff1a;<?xml version"1.0" encoding"UTF-8" ?…

合上電腦不關機

在Debian 系統上&#xff0c;如何實現合上電腦不關機的效果&#xff1f; 可以修改配置文件&#xff1a; sudo vim /etc/systemd/logind.conf1.找到 HandleLidSwitch &#xff0c;將其值改為 ignore &#xff08;處理蓋子開關為忽略&#xff09; 2.將 LidSwitchIgnoreInhibited …

服務器深夜告警?可能是攻擊前兆!

凌晨三點&#xff0c;刺耳的告警鈴聲把你從夢中驚醒&#xff1a;服務器CPU 100%&#xff0c;內存耗盡&#xff01;你手忙腳亂地登錄服務器&#xff0c;發現某個進程瘋狂占用資源。是程序Bug&#xff1f;還是業務突增&#xff1f;排查半天&#xff0c;最后在角落的日志里發現蛛絲…

重學前端003 --- CSS 顏色

文章目錄文檔聲明head顏色模型div根據在這里 Freecodecamp 實踐&#xff0c;記錄筆記總結。 文檔聲明 在文檔頂部添加 DOCTYPE html 聲明 <!DOCTYPE html>head title 元素為搜索引擎提供了有關頁面的額外信息。 它還通過以下兩種方式顯示 title 元素的內容&#xff1a…

學弟讓我幫忙寫一個學生管理系統的后端,我直接上科技

&#x1f4dd;個人主頁&#xff1a;哈__ 期待您的關注 目錄 一、飛算AI簡介 二、系統開發 2.1 需求提出 2.2 系統模塊的設計 2.3 數據庫表格設計 2.4 接口規范設計 2.5 源碼生成 三、總結 學弟這兩天有一個小組合作的任務&#xff0c;應該是培訓吧要寫一個學生管理…

《P3038 [USACO11DEC] Grass Planting G》

題目描述 給出一棵有 n 個節點的樹&#xff0c;有 m 個如下所示的操作&#xff1a; 將兩個節點之間的 路徑上的邊 的權值均加一。 查詢兩個節點之間的 那一條邊 的權值&#xff0c;保證兩個節點直接相連。 初始邊權均為 0。 輸入格式 第一行兩個整數 n,m&#xff0c;含義…

NestJS

文章的地址 NestJShttps://equinox-primrose-ceb.notion.site/NestJS-22d4b8031e0f80b39fc7fe1ff111f802 不產生測試的.spec.ts文件的配置 "generateOptions": {"spec": false }創建模型 nest g m xx 創建服務 nest g s xx 創建處理 nest g c xx CRU…