WebServer -- 注册登录

目录

🍉整体内容

🌼流程图

🎂载入数据库表

提取用户名和密码

🚩同步线程登录注册

补充解释

代码

😘页面跳转

补充解释

代码


🍉整体内容

概述

TinyWebServer 中,使用数据库连接池实现服务器访问数据库的功能,使用 POST请求 完成 注册和登录的校验工作

内容

本博客介绍同步实现注册登录功能,具体涉及:流程图,载入数据库表,提取用户名和密码,注册登录流程,以及页面跳转的代码实现

  • 流程图
    服务器从报文中提取用户名密码,接着,完成注册登录校验后,实现页面跳转逻辑
  • 载入数据库表
    将数据库的数据载入服务器
  • 提取用户名和密码
    解析报文,提取用户名和密码
  • 注册登录流程
    描述服务器注册和登录校验的流程
  • 页面跳转
    详解页面跳转机制

🌼流程图

具体地,描述了 GET 和 POST 请求下的页面跳转流程👇

🎂载入数据库表

将数据库的用户名和密码,载入服务器的 map 中,map中,key是用户名,value是密码

// 用户名和密码
map<string, string> users;void http_conn::initmysql_result(connection_pool *connPool)
{// 先从连接池取一个连接MYSQL *mysql = NULL;connectionRAII mysqlcon(&mysql, connPool); // 利用connectionRAII封装的RAII机制获取数据库连接// 在 user 表中检索username, passwd数据,浏览器输入if (mysql_query(mysql, "SELECT username,passwd FROM user")) // 执行查询语句{LOG_ERROR("SELECT error:%s\n", mysql_error(mysql)); // 输出错误信息}// 表中检索完整的结果集MYSQL_RES *result = mysql_store_result(mysql); // 存储查询结果// 返回结果集中的列数int num_fields = mysql_num_fields(result); // 获取结果集中列的数量// 返回所有字段结构的数组MYSQL_FIELD *fields = mysql_fetch_fields(result); // 获取结果集中所有字段的信息// 从结果集获取下一行,将对应用户名和密码,存入 mapwhile (MYSQL_ROW row = mysql_fetch_row(result)) // 迭代每一行数据{string temp1(row[0]); // 提取用户名string temp2(row[1]); // 提取密码users[temp1] = temp2; // 将用户名和密码存入map中}
}

提取用户名和密码

服务器解析浏览器的请求报文,当解析为POST请求时,cgi 标志位设置为1,并将请求报文的消息体赋值给 m_string,进而提取出用户名和密码

// 用户名和密码
map<string, string> users;void http_conn::initmysql_result(connection_pool *connPool)
{// 先从连接池取一个连接MYSQL *mysql = NULL;connectionRAII mysqlcon(&mysql, connPool); // 利用connectionRAII封装的RAII机制获取数据库连接// 在 user 表中检索username, passwd数据,浏览器输入if (mysql_query(mysql, "SELECT username,passwd FROM user")) // 执行查询语句{LOG_ERROR("SELECT error:%s\n", mysql_error(mysql)); // 输出错误信息}// 表中检索完整的结果集MYSQL_RES *result = mysql_store_result(mysql); // 存储查询结果// 返回结果集中的列数int num_fields = mysql_num_fields(result); // 获取结果集中列的数量// 返回所有字段结构的数组MYSQL_FIELD *fields = mysql_fetch_fields(result); // 获取结果集中所有字段的信息// 从结果集获取下一行,将对应用户名和密码,存入 mapwhile (MYSQL_ROW row = mysql_fetch_row(result)) // 迭代每一行数据{string temp1(row[0]); // 提取用户名string temp2(row[1]); // 提取密码users[temp1] = temp2; // 将用户名和密码存入map中}
}

🚩同步线程登录注册

通过 m_url 定位 / 所在位置,根据 / 后第一个字符,判断是登录还是注册校验

  • 2
    • 登录校验
  • 3
    • 注册校验

根据校验结果,跳转对应页面;此外,对数据库操作时,需要通过锁来同步

补充解释

  1. 首先通过解析URL判断用户是要进行注册还是登录操作,这是通过检查URL中的下一个字符来实现的

  2. 如果是注册操作,首先会检查数据库中是否已经存在相同的用户名,如果不存在则向数据库中插入新的用户名和密码,并在map中记录该用户的信息

  3. 如果是登录操作,会直接在map中查找用户输入的用户名和密码,如果存在且匹配,则返回欢迎页面,否则返回登录错误页面

  4. 无论是注册还是登录,操作完成后都会修改URL,将用户重定向到相应的页面,以提供反馈给用户

std::strrchr - cppreference.com

👆返回字符串中,最后一次出现该字符的位置 

std::strcpy - cppreference.com

👆strcpy(dest, src)       src 复制到 dest

std::strcat - cppreference.com

👆strcat(dest, src)     src 追加到 dest 后

代码

const char *p = strrchr(m_url, '/'); // 在字符串 m_url 中查找最后一次出现字符 '/' 的位置,并返回指向该位置的指针if (0 == m_SQLVerify) {if (*(p + 1) == '3') // 如果 URL 中的下一个字符是 '3'{// 如果是注册,先检测数据库中是否有重名// 没有重名,就增加数据char *sql_insert = (char *)malloc(sizeof(char) * 200); // 分配内存空间strcpy(sql_insert, "INSERT INTO user(username, passwd) VALUES("); // 拼接SQL语句strcat(sql_insert, "'"); // 拼接SQL语句strcat(sql_insert, name); // 拼接SQL语句strcat(sql_insert, "', '"); // 拼接SQL语句strcat(sql_insert, "password"); // 拼接SQL语句strcat(sql_insert, "')"); // 拼接SQL语句// 判断 map 中能否找到重复的用户名if (user.find(name) == users.end()) { // 如果在map中找不到重复的用户名// 向数据库插入数据时,需要通过锁来同步数据m_lock.lock(); // 加锁int res = mysql_query(mysql, sql_insert); // 执行SQL语句users.insert(pair<string, string>(name, password)); // 将用户名和密码插入map中m_lock.unlock(); // 解锁// 校验成功,跳转登录页面if (!res)strcpy(m_url, "/log.html"); // 修改URL,跳转至登录页面// 校验失败,跳转注册失败页面else strcpy(m_url, "/registerError.html"); // 修改URL,跳转至注册失败页面}else strcpy(m_url, "/registerError.html"); // 修改URL,跳转至注册失败页面}// 如果是登录,直接判断// 若浏览器输入的用户名和密码在表中可以查找到,返回 1,否则返回 0else if (*(p + 1) == '2') { // 如果 URL 中的下一个字符是 '2'if (users.find(name) != users.end() && users[name]) // 如果在map中找到用户名,并且密码正确strcpy(m_url, "/welcome.html"); // 修改URL,跳转至欢迎页面elsestrcpy(m_url, "/logError.html"); // 修改URL,跳转至登录错误页面}
}

😘页面跳转

通过 m_url 定位 / 所在位置,根据 / 后的第一个字符,使用分支语句实现页面跳转,具体👇

  • 0
    • 跳转注册页面,GET
  • 1
    • 跳转登录页面,GET
  • 5
    • 显示图片页面,POST
  • 6
    • 显示视频页面,POST
  • 7
    • 显示关注页面,POST

补充解释

malloc - cppreference.com

1)👆动态分配内存

#include <stdio.h>
#include <stdlib.h>int main(void)
{int *p1 = malloc(4*sizeof(int));  // 分配足够空间以存储一个包含 4 个整数的数组int *p2 = malloc(sizeof(int[4])); // 同上,直接命名类型int *p3 = malloc(4*sizeof *p3);   // 同上,无需重复类型名称if(p1) {for(int n=0; n<4; ++n) // 填充数组p1[n] = n*n;for(int n=0; n<4; ++n) // 打印数组内容printf("p1[%d] == %d\n", n, p1[n]);}free(p1); // 释放动态分配的内存free(p2);free(p3);
}

std::strncpy - cppreference.com

2)👆char *strncpy(char *dest, const char *src, size_t n)

src 复制到 dest,最多赋值 n 个字符,如果 src 长度 < n,dest 剩余部分空字节 \0 填充

eg:

#include <cstring>
#include <iostream>int main()
{const char* src = "hi";char dest[6] = {'a', 'b', 'c', 'd', 'e', 'f'};std::strncpy(dest, src, 5);std::cout << "The contents of dest are: ";for (char c : dest){if (c)std::cout << c << ' ';elsestd::cout << "\\0" << ' ';}std::cout << '\n';
}

前 5 个字符被替换为 h i \0 \0 \0,第 6 个字符保留原来的 f

The contents of dest are: h i \0 \0 \0 f

代码

// 找到 url 中 / 所在位置,进而判断 / 后第一个字符
const char *p = strrchr(m_url, '/');// 注册页面
if (*(p + 1) == '0') {// 分配内存以存储 URL 字符串,使用类型转换将返回的指针转换为 char 类型指针char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/register.html");// 将注册页面的 URL 复制到实际文件路径中strncpy(m_real_file + len, m_url_real, strlen(m_url_real));// 释放内存free(m_url_real);
}// 登录页面
else if (*(p + 1) == '1') {char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/log.html");// 将登录页面的 URL 复制到实际文件路径中strncpy(m_real_file + len, m_url_real, strlen(m_url_real));// 释放内存free(m_url_real);
}// 图片页面
else if (*(p + 1) == '5') {char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/picture.html");// 将图片页面的 URL 复制到实际文件路径中strncpy(m_real_file + len, m_url_real, strlen(m_url_real));// 释放内存free(m_url_real);
}// 视频页面
else if (*(p + 1) == '6') {char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/vedio.html");// 将视频页面的 URL 复制到实际文件路径中strncpy(m_real_file + len, m_url_real, strlen(m_url_real));// 释放内存free(m_url_real);
}// 关注页面
else if (*(p + 1) == '7') {char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/fans.html");// 将关注页面的 URL 复制到实际文件路径中strncpy(m_real_file + len, m_url_real, strlen(m_url_real));// 释放内存free(m_url_real);
}// 否则发送 url 实际请求的文件
else// 将原始 URL 复制到实际文件路径中strncpy(m_real_file + len, m_url, FILENAME_LEN - len - 1);

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

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

相关文章

【深度学习笔记】计算机视觉——图像增广

图像增广 sec_alexnet提到过大型数据集是成功应用深度神经网络的先决条件。 图像增广在对训练图像进行一系列的随机变化之后&#xff0c;生成相似但不同的训练样本&#xff0c;从而扩大了训练集的规模。 此外&#xff0c;应用图像增广的原因是&#xff0c;随机改变训练样本可以…

Python + Selenium —— 下拉菜单处理!

传统的下拉菜单 Select 元素&#xff0c;由一个 Select 一系列的 option 元素构成。 <select id"source" name"source"><option value"">--请选择--</option><option value"1001">网络营销</option>&…

3.3 序列式容器-deque、stack、queue、heap、priority_queue

deque 3.1定义 std::deque&#xff08;双端队列&#xff09;是C标准模板库&#xff08;STL&#xff09;中的一种容器&#xff0c;表示双端队列数据结构。它提供了在两端高效地进行插入和删除操作的能力。与vector的连续线性空间类似&#xff0c;但有所不同&#xff0c;deque动…

基于ssm旅社客房收费管理系统+vue

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

STM32使用FlyMcu串口下载程序与STLink Utility下载程序

文章目录 前言软件链接一、FlyMcu串口下载程序原理优化手动修改跳线帽选项字节其他功能 二、STLink Utility下载程序下载程序选项字节固件更新 前言 本文主要讲解使用FlyMcu配合USART串口为STM32下载程序、使用STLink Utility配合STLink为STM32下载程序&#xff0c;以及这两个…

代码随想录算法训练营第62/63天| 503.下一个更大元素II、42. 接雨水、84.柱状图中最大的矩形

文章目录 503.下一个更大元素II思路代码 42. 接雨水思路代码 84.柱状图中最大的矩形思路代码 503.下一个更大元素II 题目链接&#xff1a;503.下一个更大元素II 文章讲解&#xff1a;代码随想录|503.下一个更大元素II 思路 和739. 每日温度 (opens new window)也几乎如出一辙&…

C++/数据结构:AVL树

目录 一、AVL树的概念 二、AVL树的实现 2.1节点定义 2.2节点插入 三、AVL树的旋转 3.1新节点插入较高左子树的左侧&#xff1a;右单旋 3.2新节点插入较高右子树的右侧&#xff1a;左单旋 3.3新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋 3.4新节点插…

SLAM基础知识-卡尔曼滤波

前言&#xff1a; 在SLAM系统中&#xff0c;后端优化部分有两大流派。一派是基于马尔科夫性假设的滤波器方法&#xff0c;认为当前时刻的状态只与上一时刻的状态有关。另一派是非线性优化方法&#xff0c;认为当前时刻状态应该结合之前所有时刻的状态一起考虑。 卡尔曼滤波是…

SD NAND:为车载显示器注入智能与安全的心脏

SD NAND 在车载显示器的应用 在车载显示器上&#xff0c;SD NAND&#xff08;Secure Digital NAND&#xff09;可以有多种应用&#xff0c;其中一些可能包括&#xff1a; 导航数据存储&#xff1a; SD NAND 可以用于存储地图数据、导航软件以及车载系统的相关信息。这有助于提…

微服务day03-Nacos配置管理与Nacos集群搭建

一.Nacos配置管理 Nacos不仅可以作为注册中心&#xff0c;可以进行配置管理 1.1 统一配置管理 统一配置管理可以实现配置的热更新&#xff08;即不用重启当服务发生变更时也可以直接更新&#xff09; dataId格式&#xff1a;服务名-环境名.yaml&#xff0c;分组一般使用默认…

蓝桥杯备战刷题two(自用)

1.杨辉三角形 #include<iostream> using namespace std; #define ll long long const int N2e510; int a[N]; //1 0 0 0 0 0 0 //1 1 0 0 0 0 0 //1 2 1 0 0 0 0 //1 3 3 1 0 0 0 //1 4 6 4 1 0 0 //1 5 10 10 5 1 //前缀和思想 //第一列全为1,第二列为从0开始递增1的序…

信息检索(七):Transformer Memory as a Differentiable Search Index

Transformer Memory as a Differentiable Search Index 摘要1. 引言2. 相关工作3. 可微搜索索引3.1 索引策略3.1.1 索引方法3.1.2 文档表示策略 3.2 用于检索的 Docids 表示3.3 训练和优化 4. 实验4.1 基线4.2 实验结果 5. 结论参考资料 原文链接&#xff1a;https://proceedin…

Revit-二开之创建线性尺寸标注-(5)

创建线性尺寸标注 对应的Revit界面的按钮 线性尺寸标注源码 本篇文章实现的逻辑是从rvt文章中拾取一面墙,然后对墙添加再水平方向上的线性尺寸标注 protected override Result OnExecute(ExternalCommandData commandData, ref string message, ElementSet elements

LeetCode 刷题 [C++] 第55题.跳跃游戏

题目描述 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 题目分析 题目中…

2.1 mov、add和sub加减指令实操体验

汇编语言 1. mov操作 1.1 mov移动值 mov指令把右边的值移动到左边 mount c d:masm c: debug r ax 0034 r 073f:0100 mov ax,7t1.2 mov移动寄存器的值 把右边寄存器的值赋值给左边的寄存器 a 073f:0105 mov bx,axt1.3 mov高八位&#xff08;high&#xff09;和低八位&am…

设计模式——中介者模式(mediator pattern)

概述 如果在一个系统中对象之间的联系呈现为网状结构&#xff0c;如下图所示。对象之间存在大量的多对多联系&#xff0c;将导致系统非常复杂&#xff0c;这些对象既会影响别的对象&#xff0c;也会被别的对象所影响&#xff0c;这些对象称为同事对象&#xff0c;它们之间通过彼…

​用细节去解释,如何打造一款行政旗舰车型

高山行政加长版应该是这个级别里最大的几款 MPV 之一了&#xff0c;对于一款较大的车型&#xff0c;其最重要的是解决行驶的便利性。 这次我们就试试魏牌高山行政加长版&#xff0c;从产品本身出发看几个纬度的细节&#xff1a; 行政该如何定义加长后产品的功能变化加长之后到…

Ladder类创建梯形对象共享一个下底

package Absent;public class Chapter5 {public static void main(String[] args) {Ladder.bottom100;Ladder ladderOnenew Ladder();Ladder ladderTwonew Ladder();ladderOne.top23;ladderTwo.top34;System.out.println("ladderOne的上底&#xff1a;"ladderOne.get…

Java 数组(详细)

目录 一、数组的概述 1. 数组的理解&#xff1a; 2. 数组相关的概念&#xff1a; 3. 数组的特点&#xff1a; 4. 数组的分类&#xff1a; 5.数据结构&#xff1a; 二、一维数组 1. 一维数组的声明与初始化 2. 一维数组元素的引用&#xff1a; 3. 数组的属性&#xff1…

Scikit-Learn逻辑回归

Scikit-Learn逻辑回归 1、逻辑回归概述1.1、逻辑回归1.2、逻辑回归的优缺点1.3、逻辑回归与线性回归2、逻辑回归的原理2.1、逻辑回归的概念与原理2.2、逻辑回归的损失函数2.3、梯度下降法求解逻辑回归的最优解3、Scikit-Learn逻辑回归3.1、决策边界3.2、Scikit-Learn逻辑回归AP…