文章目录
1.引入MySQL
首先:此HTTP服务器使用线程池处理链接,每个线程如果使用cgi的话,使用进程替换,替换cgi程序。所以CGI程序支持任何后端语言eg:C/C++,Python(编写好后chomd +x 添加可执行权限即可),Java,shell等
这里为了简单,补充使用C设计数据库链接的业务测试.
下载完毕,将第三方库引入项目中 rz -e
tar xzf mysql-connector-c-6.1.11-linux-glibc2.12-x86_64.tar.gz
其中需要使用的是include 文件夹和lib文件夹,其他的都不需要可以删掉
将这两个文件夹拷贝到cgi目录下
输入下列代码测试数据库导入是否正确
#include <iostream>
#include "./include/mysql.h"
using namespace std;
int main(int argc, char const *argv[])
{
cout << mysql_get_client_info() << endl;
return 0;
}
在当前文件夹输入g++ -o test connect.cpp -I include -L lib -lmysqlclient进行编译测试
Linux Centos下载C静态库命令
sudo yum install -y glibc-static
Linux_动态库与静态库回忆
将动态库路径添加到环境变量上
export LD_LIBRARY_PATH=./lib/
LD_LIBRARY_PATH表示程序在运行时动态查找的路径,这样生成的可执行程序可以运行了
打包静态库 g++ -o connect connect.cpp -I include -L lib -lmysqlclient -lpthread -ldl -static 如果出现
解决/usr/bin/ld: cannot find -lstdc++报错
原因,没有libstdc++静态库,安装即可
locate libstdc++查找库
发现无静态库
yum search libstdc++ 查找库
下载红框的静态库即可 yum install libstdc+±static.x86_64
重新运行
g++ -o connect connect.cpp -I include -L lib -lmysqlclient -lpthread -ldl -static 发现生成完毕(忽视警告即可)
2. CGI链接数据库
服务器对浏览器uri中文加码的解码函数
// 浏览器传参时,中文字符会被编码为 UTF-8 格式,因此服务器需要对 uri 进行 decode 解码。
// 这个函数会对 uri 进行 decode 解码
std::string decode_uri(const std::string &uri)
{
std::string result; // 用于保存解码后的 uri
// 遍历 uri 中的每个字符
for (size_t i = 0; i < uri.size(); i++)
{
if (uri[i] == '%')
{ // 如果当前字符是 '%'
// 如果当前字符后面还有两个字符,则将这两个字符转换为十进制数
if (i + 2 < uri.size())
{
int value = 0;
std::istringstream iss(uri.substr(i + 1, 2));
iss >> std::hex >> value;
// 将转换后的十进制数转换为对应的字符,并添加到结果中
result += static_cast<char>(value);
i += 2;
}
else
{ // 如果当前字符后面没有两个字符,则将当前字符添加到结果中
result += uri[i];
}
}
else
{ // 如果当前字符不是 '%'
result += uri[i]; // 直接将当前字符添加到结果中
}
}
return result; // 返回解码后的 uri
}
链接数据库CGI
#include <iostream>
#include "./include/mysql.h"
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include "../tool/Util.hpp"
#include <sstream>
using namespace std;
bool GetParameter(string ¶meter)
{
// cout被重定向了,不能使用其打印
// cerr << "DEBUG CGI:" << getenv("METHOD") << endl;
std::string method = getenv("METHOD");
cerr << "DEBUG: CGI get method " << method << endl;
bool flag = true;
if ("GET" == method)
{
parameter = getenv("Get_Parameter");
// cerr << "DEBUG CGI GET Parameter:" << parameter << endl;
}
else if ("POST" == method)
{
// cerr << "DEBUG: CGI POST Parameter" << endl;
int content_length = atoi(getenv("Content_Length"));
// cerr << "DEBUG: Countent-Length: " << content_length << endl;
char ch = 0;
while (content_length > 0) // 从管道文件中写入
{
read(0, &ch, 1);
parameter += ch;
content_length -= 1;
}
cerr << "DEBUG: POST CGI end msg= " << parameter << endl;
}
else
{
// TODO 其余方法不处理,默认处理为错误
flag = false;
}
return flag;
}
bool insert(std::string &sql)
{
MYSQL *connect = mysql_init(nullptr);
mysql_set_character_set(connect, "utf8"); // 设置编码格式,防止乱码
// mysql connect+ ip + user name + password + database name + port +null+0
if (mysql_real_connect(connect, "127.0.0.1", "dodamce", "000000", "HttpSever", 3306, nullptr, 0) == nullptr)
{
cerr << "DEBUG error connecting!:" << mysql_error(connect) << endl;
return false;
}
cerr << "DEBUG succeed connecting" << endl;
int ret = mysql_query(connect, sql.c_str());
if (ret != 0)
{
cerr << "DEBUG error query!:" << mysql_error(connect) << endl;
return false;
}
cerr << "DEBUG succeed query" << endl;
mysql_close(connect);
return true;
}
// 浏览器传参时,中文字符会被编码为 UTF-8 格式,因此服务器需要对 uri 进行 decode 解码。
// 这个函数会对 uri 进行 decode 解码
std::string decode_uri(const std::string &uri)
{
std::string result; // 用于保存解码后的 uri
// 遍历 uri 中的每个字符
for (size_t i = 0; i < uri.size(); i++)
{
if (uri[i] == '%')
{ // 如果当前字符是 '%'
// 如果当前字符后面还有两个字符,则将这两个字符转换为十进制数
if (i + 2 < uri.size())
{
int value = 0;
std::istringstream iss(uri.substr(i + 1, 2));
iss >> std::hex >> value;
// 将转换后的十进制数转换为对应的字符,并添加到结果中
result += static_cast<char>(value);
i += 2;
}
else
{ // 如果当前字符后面没有两个字符,则将当前字符添加到结果中
result += uri[i];
}
}
else
{ // 如果当前字符不是 '%'
result += uri[i]; // 直接将当前字符添加到结果中
}
}
return result; // 返回解码后的 uri
}
int main(int argc, char const *argv[])
{
std::string parameter;
if (GetParameter(parameter))
{
// 数据处理 拆分参数
std::string left;
std::string right;
Util::cutString(parameter, "&", left, right);
std::string key;
std::string value;
Util::cutString(left, "=", key, value);
// 对中文名称进行解码
key = decode_uri(key);
value = decode_uri(value);
// cerr << "DEBUG: " << key << ":" << value << endl;
std::string key2;
std::string value2;
Util::cutString(right, "=", key2, value2);
// cerr << "DEBUG: " << key2 << ":" << value2 << endl;
// 插入数据库
std::string sql = "insert into user (name,passward) values (\'";
sql += value;
sql += "\',\'";
sql += value2;
sql += "\')";
cerr << "DEBUG: sql: " << sql << endl;
if (insert(sql))
{
// 返回注册成功网页
cout << "<html>";
cout << "<head><meta charset=\"UTF-8\"></head>";
cout << "<body>";
cout << "<h1>"
<< "注册成功"
<< "</h1>";
cout << "</body>";
cout << "</html>";
}
}
return 0;
}
运行截图
3. 代码位置
4. 项目总结
项目完成了HTTP GET,POST方法处理,并且对这两种方法大部分可能出错情况进行处理。模仿Java 的tomcat服务器
搭建了CGI机制:设计创建管道,父子通信,重定向,环境变量导入,数据读写机制,CGI机制支持任何后端语言,Web开发就是开发的CGI程序,常见的CGI程序语言为java和python语言,C++并不适合开发
项目扩展:
-
技术方面:
-
支持HTTP1.1长连接,浏览器可以一直使用这条连接进行通信。涉及连接管理,粘包问题
-
改成epoll版本HTTP服务器,满足更大量的请求
-
redis进行数据同步
-
将项目改为请求转发服务器,相当于代理服务器,新增代理服务器功能
-
-
应用功能拓展
- 在线博客,在线简历,在线画图板,在线视频播放器(HttpSever1.0版本已经支持,网页内嵌视频,需要高配服务器),网络计算器等等
-
项目改进点:
-
可以封装更多数据库方法,删除,更新等操作
-
支持更多HTTP方法 eg:PUT,DELETE等
-
宏处理,配置文件化
-
实现301,302转发功能
-