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); // 获取结果集中所有字段的信息

    // 从结果集获取下一行,将对应用户名和密码,存入 map
    while (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); // 获取结果集中所有字段的信息

    // 从结果集获取下一行,将对应用户名和密码,存入 map
    while (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,否则返回 0
    else if (*(p + 1) == '2') { // 如果 URL 中的下一个字符是 '2'
        if (users.find(name) != users.end() && users[name]) // 如果在map中找到用户名,并且密码正确
            strcpy(m_url, "/welcome.html"); // 修改URL,跳转至欢迎页面
        else
            strcpy(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 << ' ';
        else
            std::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);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vscode c/c++ 检测到 #include 错误。请更新 includePath。

问题背景 使用vscode打开项目后&#xff0c;头文件显示红色波浪线&#xff0c;没有引入。 检测到 #include 错误。请更新 includePath。已为此翻译单元(xxx)禁用波形曲线。 解决方法 gcc -v -E -x c - 显示所有头文件路径。 打开c_cpp_properties.json文件&#xff0c;粘贴…

Verilog Constructs、Verilog系统任务和功能

下表列出了Verilog构造在Vivado合成中的支持状态。 Verilog系统任务和功能 Vivado合成支持系统任务或功能&#xff0c;如下表所示。Vivado合成会忽略不支持的系统任务。 使用转换函数 使用以下语法对任何表达式调用$signed和$unsigned系统任务。 $signed&#xff08;expr&am…

「爬虫职海录」三镇爬虫

HI&#xff0c;朋友们好 「爬虫职海录」第三期更新啦&#xff01; 本栏目的内容方向会以爬虫相关的“岗位分析”和“职场访谈”为主&#xff0c;方便大家了解一下当下的市场行情。 本栏目持续更新&#xff0c;暂定收集国内主要城市的爬虫岗位相关招聘信息&#xff0c;有求职…

计算机设计大赛 深度学习机器视觉车道线识别与检测 -自动驾驶

文章目录 1 前言2 先上成果3 车道线4 问题抽象(建立模型)5 帧掩码(Frame Mask)6 车道检测的图像预处理7 图像阈值化8 霍夫线变换9 实现车道检测9.1 帧掩码创建9.2 图像预处理9.2.1 图像阈值化9.2.2 霍夫线变换 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分…

Redis、Elasticsearch(ES)、RocketMQ和MYSql 持久化对比

在现代大数据和分布式系统中&#xff0c;数据持久化是一个至关重要的话题。本文将针对 Redis、Elasticsearch&#xff08;ES&#xff09;、 RocketMQ和MYSql 这四种常见的数据存储和消息队列系统进行持久化方面的对比分析&#xff0c;帮助读者更好地了解它们各自的特点和适用场…

无人机镜头稳定的原理和相关算法

无人机的镜头稳定主要基于两个关键技术&#xff1a;镜头平衡技术和实时电子稳像。无人机镜头稳定的原理和相关算法主要是通过镜头平衡技术和实时电子稳像技术来保持摄像镜头的稳定性&#xff0c;从而拍摄出清晰、稳定的画面。无人机镜头稳定的原理主要是通过传感器和算法来实现…

第三百七十七回

文章目录 1. 概念介绍2. 实现方法2.1 maskFilter2.2 shader 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"两种阴影效果"相关的内容&#xff0c;本章回中将介绍如何绘制阴影效果.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概…

FCIS 2023网络安全创新大会:洞察前沿技术,探索安全新境界(附大会核心PPT下载)

随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;成为全球关注的焦点。作为网络安全领域的重要盛会&#xff0c;FCIS 2023网络安全创新大会如期而至&#xff0c;汇聚了全球网络安全领域的顶尖专家、学者、企业家和政策制定者&#xff0c;共同探讨网络安全的…

【GitHub】修改默认分支

GitHub的默认分支为main&#xff0c;但我们常常习惯使用master作为默认分支&#xff0c;那在GitHub上如何将master修改为默认分支呢&#xff1f; 全局修改 点击头像&#xff0c;选择菜单栏中的设置 输入master作为默认分支&#xff0c;然后执行updating即可&#xff01; 单项…

【数据结构和算法初阶(C语言)】顺序表+单链表经典例题图文详解(题解大合集,搭配图文演示详解,一次吃饱吃好)

目录 1.移除链表元素 1.1思路1&#xff1a;遍历删除 1. 2 思路2&#xff1a;尾插法 2.反转链表 3.链表的中间节点 3.1解题思想及过程 3.2快慢指针思想解题---变式&#xff1a;返回链表的倒数第K个节点 4.合并两个有序链表 4.1解题思想 1取小的尾插 5.反转链表 6…

mindsdb,一个超酷的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超酷的 Python 库 - mindsdb。 Github地址&#xff1a;https://github.com/mindsdb/mindsdb 在机器学习领域&#xff0c;构建和训练模型是一项复杂且耗时的任务。为了简化这个过程&#xff0c…

【C语言】linux内核generic_xdp_tx

一、中文注释 /* 在执行通用XDP时&#xff0c;我们必须绕过qdisc层和网络挖掘点&#xff0c;* 以匹配驱动内XDP的行为。*/ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog) {struct net_device *dev skb->dev; // 获取skb对应的网络设备struct netd…

Stable-Diffusion ubuntu服务器部署,报错解决方法(小白教程)

Stable Diffusion是一个深度学习模型&#xff0c;专注于生成高质量的图像。它由CompVis团队与Stability AI合作开发&#xff0c;并在2022年公开发布。这个模型使用文本提示&#xff08;text prompts&#xff09;生成详细、逼真的图像&#xff0c;是目前人工智能图像生成领域的一…

Java中使用Jsoup实现网页内容爬取与Html内容解析并使用EasyExcel实现导出为Excel文件

场景 Pythont通过request以及BeautifulSoup爬取几千条情话&#xff1a; Pythont通过request以及BeautifulSoup爬取几千条情话_爬取情话-CSDN博客 Node-RED中使用html节点爬取HTML网页资料之爬取Node-RED的最新版本&#xff1a; Node-RED中使用html节点爬取HTML网页资料之爬…

C# aes加密解密byte数组

using System.Security.Cryptography; using System.Text;namespace AESStu01;public class AesHelper {// AES加密密钥和向量&#xff08;需要保密&#xff09; private static readonly string Key "";//16长度字符串数字混合private static readonly string IV …

Sqli-labs靶场第15关详解[Sqli-labs-less-15]

Sqli-labs-Less-15 #自动化注入-SQLmap工具注入 SQLmap用户手册&#xff1a;文档介绍 - sqlmap 用户手册 由于这题是post请求&#xff0c;所以先使用burp进行抓包&#xff0c;然后将数据包存入txt文件中打包 用-r 选择目标txt文件 python sqlmap.py -r data.txt -current-db…

对象变更记录objectlog工具(持续跟新)

文章目录 前言演示代码参考仓库 前言 对于重要的一些数据&#xff0c;我们需要记录一条记录的所有版本变化过程&#xff0c;做到持续追踪&#xff0c;为后续问题追踪提供思路。 演示代码 下面我们通过一段代码演示代码&#xff0c;展示如何自动将枚举字段&#xff0c;主键关…

VLAN实验报告

实验要求&#xff1a; 实验参考图&#xff1a; 实验过程&#xff1a; r1: [r1]int g 0/0/0.1 [r1-GigabitEthernet0/0/0.1]ip address 192.168.1.1 24 [r1-GigabitEthernet0/0/0.1]dot1q termination vid 2 [r1-GigabitEthernet0/0/0.1]arp broadcast enable [r1]int g 0/0/…

Github项目推荐-LightMirrors

项目地址 https://github.com/NoCLin/LightMirrors 项目简述 “LightMirrors是一个开源的缓存镜像站服务&#xff0c;用于加速软件包下载和镜像拉取。目前支持DockerHub、PyPI、PyTorch、NPM等镜像缓存服务。 当前项目仍处于早期阶段。”–来自项目说明。 也就是说&#xff…

持续集成(CICD)- Jenkins安装插件

文章目录 Jenkins 检查自己是否有此插件安装插件&#xff1a; 以Git 插件举例&#xff08;其他插件类似&#xff09;&#xff1a; Jenkins 检查自己是否有此插件 检查自己的jenkins是否有git插件&#xff1a;进入Manage Jenkins - 往下滑动找到Global Tool Configuration - 如…