服务器做网站FTP必要性大吗,南宁企业自助建站系统,网店美工具体要求,如何创建一个属于自己的网站目录
#x1f349;整体内容
#x1f33c;流程图
#x1f382;载入数据库表
提取用户名和密码
#x1f6a9;同步线程登录注册
补充解释
代码
#x1f618;页面跳转
补充解释
代码 #x1f349;整体内容
概述 TinyWebServer 中#xff0c;使用数据库连接池实现…
目录
整体内容
流程图
载入数据库表
提取用户名和密码
同步线程登录注册
补充解释
代码
页面跳转
补充解释
代码 整体内容
概述 TinyWebServer 中使用数据库连接池实现服务器访问数据库的功能使用 POST请求 完成 注册和登录的校验工作 内容 本博客介绍同步实现注册登录功能具体涉及流程图载入数据库表提取用户名和密码注册登录流程以及页面跳转的代码实现 流程图 服务器从报文中提取用户名密码接着完成注册登录校验后实现页面跳转逻辑载入数据库表 将数据库的数据载入服务器提取用户名和密码 解析报文提取用户名和密码注册登录流程 描述服务器注册和登录校验的流程页面跳转 详解页面跳转机制 流程图 具体地描述了 GET 和 POST 请求下的页面跳转流程 载入数据库表 将数据库的用户名和密码载入服务器的 map 中map中key是用户名value是密码 // 用户名和密码
mapstring, 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进而提取出用户名和密码 // 用户名和密码
mapstring, 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 注册校验 根据校验结果跳转对应页面此外对数据库操作时需要通过锁来同步
补充解释 首先通过解析URL判断用户是要进行注册还是登录操作这是通过检查URL中的下一个字符来实现的 如果是注册操作首先会检查数据库中是否已经存在相同的用户名如果不存在则向数据库中插入新的用户名和密码并在map中记录该用户的信息 如果是登录操作会直接在map中查找用户输入的用户名和密码如果存在且匹配则返回欢迎页面否则返回登录错误页面 无论是注册还是登录操作完成后都会修改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(pairstring, 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 中的下一个字符是 2if (users.find(name) ! users.end() users[name]) // 如果在map中找到用户名并且密码正确strcpy(m_url, /welcome.html); // 修改URL跳转至欢迎页面elsestrcpy(m_url, /logError.html); // 修改URL跳转至登录错误页面}
}页面跳转 通过 m_url 定位 / 所在位置根据 / 后的第一个字符使用分支语句实现页面跳转具体 0 跳转注册页面GET1 跳转登录页面GET5 显示图片页面POST6 显示视频页面POST7 显示关注页面POST 补充解释
malloc - cppreference.com
1动态分配内存
#include stdio.h
#include stdlib.hint 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 n0; n4; n) // 填充数组p1[n] n*n;for(int n0; n4; n) // 打印数组内容printf(p1[%d] %d\n, n, p1[n]);}free(p1); // 释放动态分配的内存free(p2);free(p3);
}std::strncpy - cppreference.com
2char *strncpy(char *dest, const char *src, size_t n)
src 复制到 dest最多赋值 n 个字符如果 src 长度 ndest 剩余部分空字节 \0 填充 eg:
#include cstring
#include iostreamint 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);