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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;甚至催生出全新的业务模式。本文将深入不同行业场景&#…