Linux下的高性能轻量级Web服务器(七)

7. 注册登入

上一节弄清楚了数据库连接池的概念及实现方式后,我们继续回到 http 类部分,学习对用户的登录及注册等POST请求,服务器是如何做校验的。

当点击新用户按钮时,服务器对这个POST请求的响应是:返回用户一个登录界面;当你在用户名和密码框中输入后,你的POST请求报文中会连同你的用户名密码一起发给服务器,然后我们拿着你的用户名和密码在数据库连接池中取出一个连接用于mysql_query()进行查询,逻辑很简单,同步线程校验SYNSQL方式相信大家都能明白,但是这里社长又给出了其他两种校验方式,CGI什么的,就很容易让小白一时摸不到头脑,接下来就简单解释一下CGI是什么。



基础知识

CGI
CGI 被译作通用网关接口,它是一个运行在Web服务器上的程序,一个服务器上可以有多个 CGI 程序。这些程序通常用来执行处理表格,数据库查询等任务,而且通常会生成一个动态的 HTML 网页来响应客户的 HTTP 请求。



流程图

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);
	
	// 在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;
	}
}



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

// 判断http请求是否被完整读入
http_conn::HTTP_CODE http_conn::parse_content(char *text)
{
    if (m_read_idx >= (m_content_length + m_checked_idx))
    {
        text[m_content_length] = '\0';
        //POST请求中最后为输入的用户名和密码
        m_string = text;
        return GET_REQUEST;
    }
    return NO_REQUEST;
}


-----------------------------------------------------------------
// 以下内容是do_request 函数中,处理cgi的一部分部分

char *m_url_real = (char *)malloc(sizeof(char) * 200);
strcpy(m_url_real, "/");
strcat(m_url_real, m_url + 2);
strncpy(m_real_file + len, m_url_real, FILENAME_LEN - len - 1);
free(m_url_real);

//将用户名和密码提取出来
//user=123&password=123
char name[100], password[100];

// 以 & 为分隔符,& 前的为用户名
int i;
for (i = 5; m_string[i] != '&'; ++i)
    name[i - 5] = m_string[i];
name[i - 5] = '\0';

// 以 & 为分隔符,& 后的为密码
int j = 0;
for (i = i + 10; m_string[i] != '\0'; ++i, ++j)
    password[j] = m_string[i];
password[j] = '\0';



同步线程登录注册

		/* 
			根据标志判断是登录检测还是注册检测,即判断 / 后是 2 还是 3
			经过parse_request_line函数的处理,在此 m_url 指向 /2CGISQL.cgi 字符串
			而指针p为 const char *p = strrchr(m_url, '/');
		 */
		 
        // 如果是注册,先检测数据库中是否有重名的,没有重名的,则增加数据
        if (*(p + 1) == '3')
        {
            char *sql_insert = (char *)malloc(sizeof(char) * 200);
            strcpy(sql_insert, "INSERT INTO user(username, passwd) VALUES(");
            strcat(sql_insert, "'");
            strcat(sql_insert, name);
            strcat(sql_insert, "', '");
            strcat(sql_insert, password);
            strcat(sql_insert, "')");
			// 查看是否重名了
            if (users.find(name) == users.end())
            {
				//向数据库中插入数据时,需要通过锁来同步数据
                m_lock.lock();
                int res = mysql_query(mysql, sql_insert);
                users.insert(pair<string, string>(name, password));
                m_lock.unlock();
				
				//校验成功,跳转登录页面
                if (!res)
                    strcpy(m_url, "/log.html");
                else
                    strcpy(m_url, "/registerError.html");
            }
            else
                strcpy(m_url, "/registerError.html");
        }
        //如果是登录,直接判断
        //若浏览器端输入的用户名和密码在表中可以查找到,返回1,否则返回0
        else if (*(p + 1) == '2')
        {
            if (users.find(name) != users.end() && users[name] == password)
                strcpy(m_url, "/welcome.html");
            else
                strcpy(m_url, "/logError.html");
        }
    }



页面跳转

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

  • 0,跳转注册页面,GET
  • 1,跳转登录页面,GET
  • 5,显示图片页面,POST
  • 6,显示视频页面,POST
  • 7,显示关注页面,POST
if (*(p + 1) == '0')
{
    char *m_url_real = (char *)malloc(sizeof(char) * 200);
    strcpy(m_url_real, "/register.html");
    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");
    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");
    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, "/video.html");
    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");
    strncpy(m_real_file + len, m_url_real, strlen(m_url_real));

    free(m_url_real);
}
else
    strncpy(m_real_file + len, m_url, FILENAME_LEN - len - 1);
posted @ 2023-03-08 21:16  夜听风雨声`  阅读(231)  评论(0)    收藏  举报