最小linux web服务器系统,TinyWebServer:一个Linux下C++轻量级Web服务器(中)

好的,TinyWebServer我们讲了八个模块中的5个,还剩下数据库mysql模块,定时器timer模块,日记log模块。

(更新中~~~~~~)

mysql模块

项目中有简单的注册和登录功能,所以要使用到数据库。那么mysql模块就是数据库相关的模块,主要的其实就是数据库连接池。

首先数据库连接池是只有一个的,那么怎么保证从项目的每一个地方获取都是这个唯一的一个数据库连接池呢?欸,想到什么了?单例模式。在这里我们使用Cpp11下简洁的静态局部变量实现单例模式:

connection_pool* connection_pool::GetInstance() {

static connection_pool connPool;

return &connPool;

}

原理是是C++11标准规定了当一个线程正在初始化一个变量的时候,其他线程必须得等到该初始化完成以后才能访问它。

OK我们上面解决了池子的问题,接下来我们考虑到,WebServer要有一定的并发度,所以我们要有多个数据库连接资源放在数据库连接池,当任务线程需要数据库连接的时候就向池子申请一个。好的,那么我们便有了一个问题:怎样保证数据库连接的线程安全?

我们先得有一个保存数据库连接的数据结构list,当然我们得先保证池子(或者说list的安全)的线程安全,所以有一个池子的互斥锁lock,然后我们保证list中连接资源的安全,所以再有一个信号量reserve,用于管理池子的空闲连接数。

有了这两个池子接下来的就是比较常规的做法了:在获取/归还数据库连接资源前先用互斥锁对池子加锁,然后用信号量保证list空闲连接资源数。

2b65ef29a5872cc0e4771c25889edd04.gif

6a087676c59fa8b19d76e6bb55a32902.gif

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7

8 #include"sql_connection_pool.h"

9

10 using namespacestd;11

12 //构造函数

13 connection_pool::connection_pool() {14 this->CurConn = 0;15 this->FreeConn = 0;16 this->MaxConn = 0;17 }18

19 //单例模式,静态

20 connection_pool*connection_pool::GetInstance() {21 staticconnection_pool connPool;22 return &connPool;23 }24

25 //真正的初始化函数

26 void connection_pool::init(string url, string User, string PassWord, string DBName, int Port, unsigned intMaxConn) {27 this->url =url;28 this->Port =Port;29 this->User =User;30 this->PassWord =PassWord;31 this->DatabaseName =DBName;32

33 //先互斥锁锁住池子,创造MaxConn数据库链接

34 lock.lock();35 for (int i = 0; i < MaxConn; i++) {36 //新创建一个连接资源

37 MYSQL* con =NULL;38 con =mysql_init(con);39

40 if (con ==NULL) {41 cout << "mysqlinit Error:" << mysql_error(con)<

45 con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);46 if (con ==NULL) {47 cout << "mysql connect Error:" << mysql_error(con) <

51 //把这个资源放入链表

52 connList.push_back(con);53 ++FreeConn;54 }55

56 //初始化信号量和池子数量

57 reserve =sem(FreeConn);58 this->MaxConn =FreeConn;59

60 lock.unlock();61 }62

63 //请求获取一个连接资源

64 MYSQL*connection_pool::GetConnection() {65 MYSQL* con =NULL;66

67 if (connList.size() == 0) returnNULL;68

69 //请求一个资源,互斥锁/信号量 准备

70 reserve.wait();71 lock.lock();72

73 con = connList.front(); //从链表头取得一个资源

74 connList.pop_front();75

76 --FreeConn;77 ++CurConn;78

79 lock.unlock();80 returncon;81 }82

83 //获取空闲连接数

84 intconnection_pool::GetFreeConn() {85 return this->FreeConn;86 }87

88 //释放当前连接资源con

89 bool connection_pool::ReleaseConnection(MYSQL*con) {90 if (con == NULL) return false;91 lock.lock();92

93 connList.push_back(con);94 ++FreeConn;95 --CurConn;96

97 reserve.post();98 lock.unlock();99

100 return true;101 }102

103 //析构函数

104 connection_pool::~conne

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个 Web 服务器需要考虑很多方面,包括网络通信、请求处理、安全性等等。在本回答,我将提供一份基于 C++ 和 Ubuntu 系统Web 服务器的简单实现,希望对您有所帮助。 以下是大体实现思路: 1. 创建一个 TCP 套接字,绑定服务器的 IP 地址和端口号,并监听客户端连接请求。 2. 接收客户端连接请求,并创建一个新的线程来处理连接。 3. 在新的线程,接收客户端发送的 HTTP 请求报文,并提取出请求头和请求体。 4. 解析请求头,获取请求方法、请求 URL、HTTP 版本号等信息。 5. 根据请求 URL,读取服务器本地的文件并将其作为响应体返回给客户端。 6. 构造 HTTP 响应报文,包括响应头和响应体,并发送给客户端。 7. 关闭连接,线程退出。 以下是一个简单的代码示例,仅供参考: ```c++ #include <iostream> #include <string> #include <cstring> #include <sys/socket.h> #include <netinet/in.h> #include <pthread.h> #include <unistd.h> #include <fstream> using namespace std; const int PORT = 8080; const int BUFFER_SIZE = 1024; void handle_request(int client_sock) { char buffer[BUFFER_SIZE]; memset(buffer, 0, BUFFER_SIZE); int len = recv(client_sock, buffer, BUFFER_SIZE - 1, 0); if (len <= 0) { cout << "recv error" << endl; return; } // 解析请求头 string request(buffer, len); string method = request.substr(0, request.find(' ')); string url = request.substr(request.find(' ') + 1, request.find(' ', request.find(' ') + 1) - request.find(' ') - 1); string version = request.substr(request.find("\r\n") + 2, request.find("\r\n", request.find("\r\n") + 2) - request.find("\r\n") - 2); // 处理GET请求 if (method == "GET") { if (url == "/") { url = "/index.html"; } string file_path = "./www" + url; ifstream ifs(file_path.c_str(), ios::binary); if (!ifs) { string not_found = "HTTP/1.1 404 Not Found\r\n\r\n"; send(client_sock, not_found.c_str(), not_found.length(), 0); return; } string content((istreambuf_iterator<char>(ifs)), (istreambuf_iterator<char>())); string ok = "HTTP/1.1 200 OK\r\nContent-Length: " + to_string(content.length()) + "\r\n\r\n" + content; send(client_sock, ok.c_str(), ok.length(), 0); } // 关闭连接 close(client_sock); } void* worker(void* arg) { int client_sock = *(int*)arg; handle_request(client_sock); return NULL; } int main() { int server_sock = socket(AF_INET, SOCK_STREAM, 0); if (server_sock < 0) { cout << "socket error" << endl; return -1; } struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = INADDR_ANY; if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { cout << "bind error" << endl; return -1; } if (listen(server_sock, 10) < 0) { cout << "listen error" << endl; return -1; } while (true) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_len); if (client_sock < 0) { cout << "accept error" << endl; continue; } pthread_t tid; pthread_create(&tid, NULL, worker, (void*)&client_sock); } close(server_sock); return 0; } ``` 上述代码仅为一个简单的示例,实际的 Web 服务器需要考虑更多的细节问题,例如请求报文的解析、请求的安全性、并发处理等等。因此,如果您需要实现一个完整的 Web 服务器,建议参考更多的资料和实现方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值