WebServer -- 注册登录

news2024/11/17 23:45:57

目录

🍉整体内容

🌼流程图

🎂载入数据库表

提取用户名和密码

🚩同步线程登录注册

补充解释

代码

😘页面跳转

补充解释

代码


🍉整体内容

概述

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);

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

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

相关文章

C++指针(三)

个人主页:PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 文章目录 前言 1.字符指针 1.1字符指针的概念 1.2字符指针的用处 1.3字符指针的操作 1.3.1定义 1.3.2初始化 1.4字符指针使用注意事项 2.数组参数&#xff0c;指针参数 2.1数组参数 2.1.1数组参数的概念 2.1…

NCT 全国青少年编程图形化编程(Scratch)等级考试(一级)模拟测试H

202312 青少年软件编程等级考试Scratch一级真题 第 1 题 【 单选题 】 以下说法合理的是( ) A :随意点开不明来源的邮件 B :把密码设置成 abc123 C :在虚拟社区上可以辱骂他人 D :在改编他人的作品前&#xff0c; 先征得他人同意 正确答案&#xff1a; D 试题解析&…

python模块和包概念与使用

python模块和包概念与使用 Python模块与包的关键概念 在Python编程中&#xff0c;模块和包是代码组织和管理的基石。以下是关于Python模块与包的核心要点&#xff1a; 模块&#xff1a; 模块是一个包含Python代码的.py文件&#xff0c;它可以定义函数、类、变量等。通过导入模…

水经微图Web版1.6.0发布

让每一个人都有自己的地图&#xff01; 水经微图&#xff08;简称“微图”&#xff09;新版已上线&#xff0c;在该版本中主要新增了点线面图层分组样式设置、图层排序并按序绘制、KML支持矢量符号的存储、KML支持态势标绘要素存储和新增历史地图文本样式等。 现在&#xff0…

Leetcoder Day27| 贪心算法part01

语言&#xff1a;Java/Go 理论 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 什么时候用贪心&#xff1f;可以用局部最优退出全局最优&#xff0c;并且想不到反例到情况 贪心的一般解题步骤 将问题分解为若干个子问题找出适合的贪心策略求解每一个子…

使用plasmo框架开发浏览器插件,注入contents脚本和给页面添加UI组件

plasmo&#xff1a;GitHub - PlasmoHQ/plasmo: &#x1f9e9; The Browser Extension Framework plasmo是一个开发浏览器插件的框架&#xff0c;支持使用react和vue等技术&#xff0c;而且不用手动管理manifest.json文件&#xff0c;框架会根据你在框架中的使用&#xff0c;自…

美团分布式 ID 框架 Leaf 介绍和使用

一、Leaf 在当今日益数字化的世界里&#xff0c;软件系统的开发已经成为了几乎所有行业的核心。然而&#xff0c;随着应用程序的规模不断扩大&#xff0c;以及对性能和可扩展性的需求不断增加&#xff0c;传统的软件架构和设计模式也在不断地面临挑战。其中一个主要挑战就是如…

SAP EC-CS如何实现自动抵消

SAP EC-CS 是SAP 比较早的合并方案&#xff0c;尽管后面有很多其他的方案作为替代&#xff0c;但 EC-CS 因为其成熟性&#xff0c;在集团合并单元不多的情况下&#xff0c;也可以作为一个不错的合并解决方案。可以说&#xff0c;会计报表合并一个核心就是实现抵消的处理&#x…

nginx------------缓存功能 ip透传 负载均衡 (六)

一、http 协议反向代理 &#xff08;一&#xff09;反向代理示例:缓存功能 缓存功能可以加速访问&#xff0c;如果没有缓存关闭后端服务器后&#xff0c;图片将无法访问&#xff0c;缓存功能默认关闭&#xff0c;需要开启。 ​ proxy_cache zone_name | off; 默认off #指明调…

2024全新手机软件下载应用排行、平台和最新发布网站,采用响应式织梦模板

这是一款简洁蓝色的手机软件下载应用排行、平台和最新发布网站&#xff0c;采用响应式织梦模板。 主要包括主页、APP列表页、APP详情介绍页、新闻资讯列表、新闻详情页、关于我们等模块页面。 地 址 &#xff1a; runruncode.com/php/19703.html 软件程序演示图&#xff1a;…

C语言中的字符魔法:大小写转换的艺术

引言 在C语言的世界里&#xff0c;字符处理是一项基础且重要的任务。字符作为编程中最基本的元素之一&#xff0c;承担着信息展示、数据交互等多重角色。特别是在处理文本信息时&#xff0c;字符的转换和识别显得尤为重要。大小写字母的转换就是其中一个常见的需求&#xff0c…

串及BF朴素查找算法(学习整理):

关于串的相关定义&#xff1a; 串&#xff1a;用‘ ’表示的字符序列空串&#xff1a;包含零个字符的串子串&#xff1a;包含传本身和空串的子串 eg: abc(,a,b,c,ab,bc,ac,abc)共7个&#xff1a;串的长度的阶乘1&#xff08;空串&#xff09;真子串&#xff1a;不包含自身的所…

linux安装matlab获取许可证

1.点击许可证 2. 3. 4. 4.主机ID 打开linux输入 /sbin/ifconfigether后边的就是 6.计算机登录名 打开linux输入 whoami7. 8. 9.

【已亲测有效】如何彻底删除nodejs,避免影响安装新版本

第一步开始菜单搜索uninstall node.js&#xff0c;点击之后等待删除&#xff08;删除node_modules文件夹以及以下这些文件&#xff09; 第二步手动删除nodejs下载位置的其他文件夹。&#xff08;就是另外自己新建的两个文件夹node_cache和node_global&#xff09; 到这里其实应…

LDR6328芯片:智能家居时代的小家电充电革新者

在当今的智能家居时代&#xff0c;小家电的供电方式正变得越来越智能化和高效化。 利用PD&#xff08;Power Delivery&#xff09;芯片进行诱骗取电&#xff0c;为后端小家电提供稳定电压的技术&#xff0c;正逐渐成为行业的新宠。在这一领域&#xff0c;LDR6328芯片以其出色的…

什么是VR数字文化遗产保护|元宇宙文旅

VR数字文化遗产保护是指利用虚拟现实&#xff08;VR&#xff09;技术来保护和传承文化遗产。在数字化时代&#xff0c;许多珍贵的文化遗产面临着自然衰退、人为破坏或其他因素造成的威胁。通过应用VR技术&#xff0c;可以以全新的方式记录、保存和展示文化遗产&#xff0c;从而…

C语言指针(4):函数在指针中的进阶应用

1、回调函数 回调函数就是⼀个通过函数指针调⽤的函数。函数参数的形式为函数指针类型。 当你把函数/函数的地址作为参数传递给相应函数是&#xff0c;如果这个指针被用来调用其所指向的函数时&#xff0c;被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用的&…

workstation 用途

一 workstation 用途 强大的桌面虚拟化 允许创造多种操作系统可以不用重启就跨不同操作系统进行操作可以提供隔离的安全环境 连接到vsphere 可以远程登陆服务器管理物理主机和虚拟主机任何时间都可登陆提高虚拟机效率 为任何平台开发和测试 1&#xff09;借助一台单一本地…

【AI Agent系列】【MetaGPT多智能体学习】6. 多智能体实战 - 基于MetaGPT实现游戏【你说我猜】(附完整代码)

本系列文章跟随《MetaGPT多智能体课程》&#xff08;https://github.com/datawhalechina/hugging-multi-agent&#xff09;&#xff0c;深入理解并实践多智能体系统的开发。 本文为该课程的第四章&#xff08;多智能体开发&#xff09;的第四篇笔记。今天我们来完成第四章的作…

【解决】虚幻导入FBX模型不是一个整体

问题&#xff1a; 现在有一个汽车的fbx模型&#xff0c;导入虚幻引擎&#xff0c;导入后变成了很多汽车零件模型。 解决&#xff1a; 把“合并网格体”勾选上&#xff0c;解决问题。