C++ 登錄狀態機項目知識筆記

C++ 登錄狀態機項目知識筆記

1. 項目源碼

1.1 login_state_machine.h

#pragma once#include <string>// 登錄狀態枚舉
enum class LoginState { IDLE, AUTHENTICATING, SUCCESS, FAILURE, LOCKED };// 登錄事件枚舉
enum class LoginEvent { REQUEST, SUCCESS, FAILURE, RETRY, TIMEOUT, LOGOUT };// 登錄數據結構體
struct LoginData {std::string username;std::string password;int attempt_count;
};// 登錄狀態機類
class LoginStateMachine {
private:LoginState current_state;LoginData login_data;bool validateCredentials(const LoginData& data);void grantAccess();void showError();void lockAccount();public:LoginStateMachine();void handleEvent(LoginEvent event, const LoginData* data);LoginState getCurrentState() const;void setCurrentState(LoginState state);
};

1.2 login_state_machine.cpp

#include "login_state_machine.h"
#include <iostream>
#include <string.h>// 構造函數,初始化狀態和數據
LoginStateMachine::LoginStateMachine() : current_state(LoginState::IDLE) {login_data.attempt_count = 0;
}// 處理事件的核心方法
void LoginStateMachine::handleEvent(LoginEvent event, const LoginData* data) 
{static int count = 0;if (data != nullptr) {const char* login_username = login_data.username.c_str();if(strlen(login_username) == strspn(login_username," /t")){login_data = *data;}else if(!strcasecmp(data->username.c_str(),login_data.username.c_str())){login_data.password = data->password;}else{login_data = *data;}}switch (current_state) {case LoginState::IDLE:std::cout << "LoginState::IDLE" << std::endl;std::cout << login_data.username << "    " << login_data.password << std::endl;if (event == LoginEvent::REQUEST) {current_state = LoginState::AUTHENTICATING;if (validateCredentials(login_data)) {handleEvent(LoginEvent::SUCCESS, nullptr);} else {handleEvent(LoginEvent::FAILURE, nullptr);}}break;case LoginState::AUTHENTICATING:std::cout << "LoginState::AUTHENTICATING" << std::endl;std::cout << login_data.username << "    " << login_data.password << std::endl;if (event == LoginEvent::SUCCESS) {grantAccess();login_data.attempt_count = 0; // 重置嘗試次數current_state = LoginState::SUCCESS;} else if (event == LoginEvent::FAILURE) {login_data.attempt_count++;if (login_data.attempt_count >= 3) {lockAccount();current_state = LoginState::LOCKED;} else {showError();current_state = LoginState::FAILURE;}} else if (event == LoginEvent::TIMEOUT) {showError();current_state = LoginState::FAILURE;}break;case LoginState::SUCCESS:std::cout << "LoginState::SUCCESS" << std::endl;std::cout << login_data.username <<"    "  << login_data.password << std::endl;if (event == LoginEvent::LOGOUT) {current_state = LoginState::IDLE;}break;case LoginState::FAILURE:std::cout << "LoginState::FAILURE" << std::endl;std::cout << login_data.username<< "    "  << login_data.password << std::endl;if (event == LoginEvent::RETRY) {current_state = LoginState::IDLE;event = LoginEvent::REQUEST;handleEvent(LoginEvent::REQUEST, &login_data);} else if (event == LoginEvent::LOGOUT) {current_state = LoginState::IDLE;std::cout << "Logout!!!" << std::endl;}else{count++;std::cout << "FAILURE count:" << count << std::endl;}break;case LoginState::LOCKED:std::cout << "LoginState::LOCKED" << std::endl;std::cout << login_data.username << "    "  << login_data.password << std::endl;// 鎖定狀態下不處理任何事件break;}
}// 驗證憑據的方法
bool LoginStateMachine::validateCredentials(const LoginData& data) 
{// 簡單的驗證邏輯:用戶名和密碼都是 "admin"return data.username == "admin" && data.password == "admin";
}// 授權訪問的方法
void LoginStateMachine::grantAccess() 
{std::cout << "Access granted! Welcome." << std::endl;
}// 顯示錯誤信息的方法
void LoginStateMachine::showError() 
{std::cout << "Authentication failed. Attempts: " << login_data.attempt_count << std::endl;
}// 鎖定賬戶的方法
void LoginStateMachine::lockAccount() 
{std::cout << "Account locked due to too many failed attempts." << std::endl;
}// 獲取當前狀態
LoginState LoginStateMachine::getCurrentState() const 
{return current_state;
}// 設置當前狀態
void LoginStateMachine::setCurrentState(LoginState state) 
{current_state = state;
}

1.3 main.cpp

#include "login_state_machine.h"
#include <cassert>
#include <iostream>// 測試登錄狀態機
int main() 
{LoginStateMachine sm;LoginData data{"admin", "123", 0};// 第一次嘗試sm.handleEvent(LoginEvent::REQUEST, &data);sm.handleEvent(LoginEvent::FAILURE, nullptr);std::cout << "-------------------------------------" << std::endl;// 第二次嘗試data.password = "wrong";sm.handleEvent(LoginEvent::RETRY, &data);sm.handleEvent(LoginEvent::FAILURE, nullptr);std::cout << "-------------------------------------" << std::endl;// 第三次嘗試 - 賬戶鎖定data.password = "stillwrong";sm.handleEvent(LoginEvent::RETRY, &data);sm.handleEvent(LoginEvent::FAILURE, nullptr);std::cout << "-------------------------------------" << std::endl;// 驗證狀態為LOCKEDassert(sm.getCurrentState() == LoginState::LOCKED);return 0;
}

1.4 Makefile

# 添加目標
TGT := appCUR_DIR := $(shell pwd)# 自動發現源文件
SRC := $(wildcard *.cpp)
OBJ := $(patsubst %.cpp,%.o,$(SRC))# 自動發現頭文件目錄
HEADER_DIRS := $(shell find . -name "*.h" -exec dirname {} \; | sort | uniq)
INCLUDE_FLAGS := $(addprefix -I,$(HEADER_DIRS))# cppflags 設置
CPPFLAGS := -pthread $(INCLUDE_FLAGS)# cxxflags 設置 - 添加 -g 并移除 -O2 以支持調試
CXXFLAGS := -Wall -g -std=c++11# 添加調試版本和發布版本的不同配置
ifdef DEBUG
CXXFLAGS += -O0
else
CXXFLAGS += -O2
endif# 默認目標
all: $(TGT)@echo "構建成功"# 鏈接目標
$(TGT): $(OBJ)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@# 編譯規則
%.o: %.cpp$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@# 清理目標
clean:
ifneq ($(wildcard $(OBJ)),)@rm $(OBJ)
else@echo "無需清理對象文件"
endif
ifneq ($(wildcard $(TGT)),)@rm $(TGT)
else@echo "無需清理可執行文件"
endif# 僅清理對象文件
obj_clean:
ifneq ($(wildcard $(OBJ)),)@rm $(OBJ)
else@echo "無需清理對象文件"
endif.PHONY: obj_clean clean all

1.5 tasks.json

{"version": "2.0.0","tasks": [{"label": "Build with Makefile","type": "shell","command": "make","args": ["DEBUG=1"],"group": "build","problemMatcher": ["$gcc"],"options": {"cwd": "${workspaceFolder}"},"detail": "使用Makefile構建項目(調試模式)"},{"label": "Build Release with Makefile","type": "shell","command": "make","args": [],"group": "build","problemMatcher": ["$gcc"],"options": {"cwd": "${workspaceFolder}"},"detail": "使用Makefile構建項目(發布模式)"},{"label": "Clean with Makefile","type": "shell","command": "make","args": ["clean"],"group": "build","options": {"cwd": "${workspaceFolder}"},"detail": "清理構建文件"}]
}

1.6 launch.json

{"version": "0.2.0","configurations": [{"name": "Debug C++ Application","type": "cppdbg","request": "launch","program": "${workspaceFolder}/app","args": [],"stopAtEntry": false,"cwd": "${workspaceFolder}","environment": [],"externalConsole": false,"MIMode": "gdb","setupCommands": [{"description": "Enable pretty-printing for gdb","text": "-enable-pretty-printing","ignoreFailures": true},{"description": "Set breakpoint at main","text": "break main","ignoreFailures": true}],"preLaunchTask": "Build with Makefile","miDebuggerPath": "/usr/bin/gdb"},{"name": "Run C++ Application","type": "cppdbg","request": "launch","program": "${workspaceFolder}/app","args": [],"stopAtEntry": false,"cwd": "${workspaceFolder}","environment": [],"externalConsole": false,"MIMode": "gdb","setupCommands": [{"description": "Enable pretty-printing for gdb","text": "-enable-pretty-printing","ignoreFailures": true}],"preLaunchTask": "Build Release with Makefile","miDebuggerPath": "/usr/bin/gdb"}]
}

2. 構建手順和說明

2.1 環境準備

  1. 確保遠程Ubuntu系統已安裝以下工具:

    • g++ (GNU C++編譯器)
    • gdb (GNU調試器)
    • make (構建工具)
    • VSCode Remote-SSH擴展
  2. 使用以下命令安裝所需工具:

sudo apt update
sudo apt install g++ gdb make

2.2 項目設置

  1. 在遠程Ubuntu上創建項目目錄:
mkdir login_state_machine
cd login_state_machine
  1. 將上述源碼文件保存到項目目錄中

  2. 使用VSCode Remote-SSH連接到遠程Ubuntu,打開項目目錄

2.3 構建和運行

  1. 使用Makefile手動構建

    # 調試版本
    make DEBUG=1# 發布版本
    make# 清理構建文件
    make clean
    
  2. 使用VSCode任務構建

    • 按下Ctrl+Shift+P,輸入"Tasks: Run Task"
    • 選擇相應的構建任務(調試/發布/清理)
  3. 使用VSCode調試

    • 按下F5啟動調試(使用調試版本)
    • 在調試側邊欄選擇"Run C++ Application"運行發布版本

2.4 測試程序

運行編譯后的程序:

./app

預期輸出:

LoginState::IDLE
admin    123
LoginState::AUTHENTICATING
admin    123
Authentication failed. Attempts: 1
LoginState::FAILURE
admin    123
-------------------------------------
LoginState::IDLE
admin    wrong
LoginState::AUTHENTICATING
admin    wrong
Authentication failed. Attempts: 2
LoginState::FAILURE
admin    wrong
-------------------------------------
LoginState::IDLE
admin    stillwrong
LoginState::AUTHENTICATING
admin    stillwrong
Authentication failed. Attempts: 3
Account locked due to too many failed attempts.
LoginState::LOCKED
admin    stillwrong
-------------------------------------

3. 關鍵部分解釋和說明

3.1 狀態機設計模式

狀態機是一種行為設計模式,允許對象在其內部狀態改變時改變其行為。在這個項目中:

  1. 狀態(State):定義了對象在不同情況下的行為
  2. 事件(Event):觸發狀態轉換的外部輸入
  3. 轉換(Transition):狀態之間根據事件發生的遷移
REQUEST事件
SUCCESS事件
FAILURE事件(嘗試<3次)
FAILURE事件(嘗試≥3次)
RETRY事件
LOGOUT事件
任何事件(鎖定狀態)
IDLE
AUTHENTICATING
SUCCESS
FAILURE
LOCKED

3.2 Makefile 關鍵概念

  1. 變量定義:使用變量簡化和維護構建規則
  2. 自動發現:使用wildcardfind自動發現源文件和頭文件
  3. 模式規則:使用%.o: %.cpp定義通用編譯規則
  4. 條件編譯:使用ifdef區分調試和發布版本

3.3 VSCode 調試配置

  1. preLaunchTask:調試前自動執行構建任務
  2. problemMatcher:解析編譯器輸出,在IDE中顯示錯誤
  3. setupCommands:配置GDB初始化命令
  4. 變量替換:使用${workspaceFolder}等變量使配置更通用

3.4 數據管理策略

狀態機中使用了智能數據更新策略:

if (data != nullptr) 
{const char* login_username = login_data.username.c_str();if(strlen(login_username) == strspn(login_username," /t")){login_data = *data; // 初始數據或不同用戶}else if(!strcasecmp(data->username.c_str(),login_data.username.c_str())){login_data.password = data->password; // 同一用戶更新密碼}else{login_data = *data; // 不同用戶}
}

這種策略確保:

  1. 同一用戶的多次嘗試只更新密碼字段
  2. 不同用戶的嘗試會完全更新登錄數據
  3. 避免不必要的數據復制

4. 進階功能和擴展建議

4.1 單元測試集成

可以考慮集成Google Test等單元測試框架:

# 在Makefile中添加測試目標
TEST_TGT := test_app
TEST_SRC := $(wildcard test_*.cpp)
TEST_OBJ := $(patsubst %.cpp,%.o,$(TEST_SRC))$(TEST_TGT): $(filter-out main.o,$(OBJ)) $(TEST_OBJ)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -lgtest -lgtest_main -pthread -o $@test: $(TEST_TGT)./$(TEST_TGT)

4.2 日志系統增強

可以添加更完善的日志系統:

// 簡單的日志級別定義
enum class LogLevel { DEBUG, INFO, WARNING, ERROR };// 日志記錄函數
void logMessage(LogLevel level, const std::string& message) {// 根據級別輸出不同顏色的日志// 可以添加時間戳、文件名和行號等信息
}

4.3 配置文件支持

添加配置文件支持,使驗證邏輯更靈活:

// 從配置文件加載有效憑據
std::map<std::string, std::string> loadCredentials(const std::string& filename) {std::map<std::string, std::string> credentials;// 讀取文件并解析用戶名-密碼對return credentials;
}// 修改驗證邏輯使用配置文件
bool LoginStateMachine::validateCredentials(const LoginData& data) {static auto valid_credentials = loadCredentials("credentials.cfg");auto it = valid_credentials.find(data.username);return it != valid_credentials.end() && it->second == data.password;
}

4.4 超時處理增強

添加更完善的超時處理機制:

#include <chrono>
#include <thread>// 在狀態機中添加超時處理
void LoginStateMachine::startTimeoutTimer(int seconds) {std::thread([this, seconds]() {std::this_thread::sleep_for(std::chrono::seconds(seconds));if (this->current_state == LoginState::AUTHENTICATING) {this->handleEvent(LoginEvent::TIMEOUT, nullptr);}}).detach();
}

5. 故障排除和常見問題

5.1 編譯問題

  1. 頭文件找不到:檢查HEADER_DIRS是否正確發現了頭文件目錄
  2. 鏈接錯誤:確保所有必要的源文件都包含在SRC變量中
  3. 權限問題:確保對項目目錄有讀寫權限

5.2 調試問題

  1. 斷點不生效:確保使用DEBUG=1編譯以生成調試信息
  2. 變量查看不到:檢查GDB的pretty-printing是否正常工作
  3. 調試器連接失敗:確認miDebuggerPath指向正確的GDB路徑

5.3 運行時問題

  1. 狀態轉移異常:檢查事件處理邏輯,特別是遞歸調用部分
  2. 數據不一致:驗證數據更新策略是否正確處理了各種情況
  3. 多線程問題:如果添加了超時處理,注意線程安全問題

這個項目提供了一個完整的C++狀態機實現,結合了現代開發工具鏈的最佳實踐,是學習C++編程、狀態機設計和開發環境配置的優秀示例。

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

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

相關文章

docker-nacos-v3

nacos官網&#xff1a; Redirecting to: https://nacos.io/ 服務發現和服務健康監測 Nacos 支持基于 DNS 和基于 RPC 的服務發現。服務提供者使用 原生SDK、OpenAPI、或一個獨立的Agent TODO注冊 Service 后&#xff0c;服務消費者可以使用DNS TODO 或HTTP&API查找和發現服…

DevOps 詳解:文化、實踐與工具鏈

目錄一、DevOps 定義與核心目標二、DevOps 關鍵原則與實踐1. 持續集成&#xff08;CI&#xff0c;Continuous Integration&#xff09;2. 持續交付&#xff08;CD&#xff0c;Continuous Delivery&#xff09;3. 持續部署&#xff08;Continuous Deployment&#xff09;4. 監控…

人工智能之數學基礎:常用的連續型隨機變量的分布

本文重點 本文將介紹概率中非常重要的連續型隨機變量的分布,主要有均勻分布、指數分布、正態分布 均勻分布 若隨機變量X的概率密度為: 如果概率密度函數如上所示,則稱X服從區間[ a, b]上的均勻分布,記作X~U[a,b] 均勻分布的概率密度函數的計算如下: 指數分布 指數分布…

【開題答辯全過程】以 校園幫幫團跑腿系統的設計與實現為例,包含答辯的問題和答案

個人簡介一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧。感謝大家的…

Milvus 向量數據庫開發實戰指南

Milvus向量數據庫是什么&#xff1f;-CSDN博客 一、核心概念解析 1.1 基礎概念 1.1.1 Bitset&#xff08;位集&#xff09; 高效的數據表示方式&#xff0c;使用位數組替代傳統數據類型 默認情況下&#xff0c;位值根據特定條件設置為 0 或 1 1.1.2 通道機制 PChannel&am…

vcruntime140.dll丟失解決辦法

解決辦法 安裝Microsoft Visual C Redistributable https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?viewmsvc-170

LabVIEW實現跨 VI 簇按鈕控制功能

?在 LabVIEW 開發場景中&#xff0c;常需實現不同 VI 間的交互操作。本功能借助 VI Server 技術&#xff0c;突破 VI 邊界&#xff0c;實現對目標 VI 中簇內按鈕控件的屬性讀取與控制&#xff0c;為多 VI 協同、對VI里已經實現的功能&#xff0c;可以在其他VI中直接使用&#…

JS箭頭函數

JavaScript 的箭頭函數 (Arrow Function) 是 ES6 (ECMAScript 2015) 引入的一種重要的函數語法特性&#xff0c;它用更簡潔的方式定義函數&#xff0c;并改變了 this 的綁定行為。 箭頭函數和傳統函數的主要區別&#xff1a;特性箭頭函數傳統函數語法更簡潔&#xff0c;省略 fu…

linux內核 - 文件系統相關的幾個概念介紹

介紹文件系統之前&#xff0c;先了解下存儲管理的幾個概念&#xff1a;1. 硬盤&#xff1a;是最底層的存儲介質&#xff0c;比如 /dev/sda, /dev/nvme0n1. 一個物理硬盤就是一個塊設備&#xff0c;未經處理是只能順序讀寫二進制數據。 2. 分區&#xff1a;就是在硬盤上劃分出不…

邊緣計算(Edge Computing)+ AI:未來智能世界的核心引擎

邊緣計算&#xff08;Edge Computing&#xff09; AI&#xff1a;未來智能世界的核心引擎 文章目錄邊緣計算&#xff08;Edge Computing&#xff09; AI&#xff1a;未來智能世界的核心引擎摘要什么是邊緣計算&#xff1f;為什么需要邊緣計算&#xff1f;1. 延遲問題2. 帶寬壓力…

計算機視覺與深度學習 | ORB-SLAM3算法原理與Matlab復現指南

文章目錄 一、算法核心原理 1.1 系統架構概述 1.2 數學模型基礎 1.2.1 狀態估計框架 1.2.2 視覺-慣導融合模型 1.3 關鍵創新點 二、關鍵模塊實現細節 2.1 ORB特征提取與匹配 2.2 地圖初始化 2.3 視覺-慣導融合 2.4 回環檢測與優化 三、Matlab復現思路 3.1 系統模塊劃分 3.2 核心…

分布式光伏模式怎么選?從 “憑經驗” 到 “靠數據”,iSolarBP 幫你鎖定最優解

iSolarBP-陽光新能源旗下分布式光伏光儲智能評估設計軟件 iSolarBP是陽光新能源打造的分布式光伏/光儲項目智能設計平臺。提供無人機自動勘測、3D建模、高精度發電仿真、光儲容量優化與經濟分析一站式服務&#xff0c;助力開發者提升效率、降低成本和優化投資收益。https://iso…

MATLAB R2010b系統環境(四)MATLAB幫助系統

一、幫助命令MATLAB幫助命令包括help、lookfor以及模糊查詢。1.1 help命令在命令窗口中直接輸入help或help加函數名。&#xff08;1&#xff09;help&#xff1a;顯示當前幫助系統中所包含的所有項目&#xff0c;即搜索路徑中所有的目錄名稱&#xff0c;如下圖&#xff1a;&…

“便農惠農”智慧社區系統(代碼+數據庫+LW)

摘要 隨著城市化進程加速和信息技術快速發展&#xff0c;傳統社區管理模式已難以滿足現代社區高效管理和居民多元化服務需求。為解決社區管理中的信息孤島問題、提升服務效率并增強居民生活體驗&#xff0c;本文設計并實現了一套基于Spring Boot框架的智慧社區管理系統。該系統…

智慧金融服務平臺問題剖析與改進策略

智慧金融服務平臺問題剖析與改進策略 在數字化浪潮的推動下&#xff0c;智慧金融服務平臺蓬勃發展&#xff0c;為用戶帶來了便捷的金融服務體驗。然而&#xff0c;隨著用戶數量的不斷增加和業務的日益復雜&#xff0c;平臺也暴露出一些問題&#xff0c;其中數據準確性不足、異常…

【Vue2?】Vue2 入門之旅(三):數據與方法

在前兩篇文章中&#xff0c;我們學習了 Vue 的基礎和模板語法。本篇我們將深入 數據與方法&#xff0c;理解 data、methods、computed、watch 的作用和區別。 目錄 datamethodscomputedwatch小結 data Vue 實例中的 data 是數據源&#xff0c;模板會自動響應其中的變化。 &l…

自動化測試時,chrome瀏覽器啟動后閃退的問題

之前運行的好好的&#xff0c;最近再次練習時發現會閃退&#xff0c;然后發現是驅動版本老的問題 &#xff08;1&#xff09;下載與之匹配的驅動器版本 Chrome for Testing availability 找到與Chrome版本前3位相同的目錄&#xff0c;下載對應系統的壓縮包 &#xff08;2&am…

Dynamics 365 XrmToolBox工具之Clone Field Definitions

好久沒有分享XrmToolBox的組件了&#xff0c;今天要分享的是下圖中這個組件在建實體的時候&#xff0c;我們經常會碰到實體間一些字段存在重復&#xff0c;或者都可以直接復制黏貼加一些少量修改就可以生成第二個實體&#xff0c;但如果僅從D365本身來說&#xff0c;要做到復制…

UBUNTU之Onvif開源服務器onvif_srvd:1、編譯

下載源碼 編譯時會下載東西&#xff0c;有可能需要VPN。 https://github.com/KoynovStas/onvif_srvd https://github.com/KoynovStas/onvif_srvd/tags 解壓準備工作 sudo apt install -y flex bison byacc make cmake m4# for support encryption and WS-Security # 在低版…

深度學習跨領域應用探索:從技術落地到行業變革

深度學習不再是實驗室里的 “高精尖技術”&#xff0c;而是滲透到各行各業的 “效率引擎”。它憑借強大的數據擬合與特征提取能力&#xff0c;在計算機視覺、自然語言處理、金融風控等領域打破傳統技術瓶頸&#xff0c;甚至催生出全新的業務模式。本文將深入不同行業場景&#…