Linux下C++轻量级WebServer服务器 TinyWebServer(一)
主函数解析
#include "config.h"
int main(int argc,char *agrv[])
{
//需要修改的数据库信息,登录名,密码,库名
string user = "root";
string pass = "123456";
string databasename="qgydb";
//命令行解析
Config config;
config.parse_arg(argc,argv);
WebServer server;
//初始化
server.init(config.PORT,user,passwd,databasename,config.LOGWrite,
config.OPT_LINGER,config.TRIGMode,config.sql_num,config.thread_num,config.close_log,config.actor_model);
//日志
server.log_write();
//数据库
server.sql_pool();
//线程池
server.thread_pool();
//触发模式
server.trig_mode();
//监听
server.eventListen();
//运行
server.eventLoop();
return 0;
}
WebServer类
重要性
WebServer类封装了服务器的主要逻辑,包括初始化、事件循环和事件处理,比较核心,所以选择看完main.cpp后看WebServer类
WebServer.h具体实现
#ifndef WEBSERVER_H
#define WEBSERVER_H
/*
包含网络编程必需的 socket/epoll 等头文件
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdilb.h>
#include <cassert>
#include <sys/epoll.h>
//线程池和http处理模块
#include "./threadpool/threadpool.h"
#include "./http/http_conn.h"
const int MAX_FD = 65536;//最大文件描述符
const int MAX_EVENT_NUMBER = 10000;//epoll最大事件数
const int TIMESLOT = 5;//定时器超时时间(秒)
class WebServer
{
public:
WebServer();//构造函数
~WebServer();//析构函数
void init(int port,string user,string passWord,string databaseName,int log_write,int opt_linger,int trigmode, int sql_num,int thread_num,int close_log,int actor_model);//接收所有配置参数进行初始化
/*
1.监听端口
2.数据库用户名
3.数据库密码
4.数据库名
5.日志写入方式
6.连接关闭选项
7.触发模式
8.数据库连接数
9.线程数量
10.日志开关
11.并发模型
*/
//模块初始化方法
void thread_pool();//初始化线程池
void sql_pool();//初始化数据库连接池
void log_write();//初始化日志系统
void trig_mode();//设置触发模式
//核心网络方法
void eventListen();//创建监听socke和epoll
void eventLoop();//主事件循环
//事件处理方法
bool dealclientdata();//处理新客户端连接
bool dealwithsignal(bool& timeout,bool& stop_server);//处理信号
void dealwithread(int sockfd);//处理读事件
void dealwithwrite(int sockfd);//处理写事件
//定时器管理
void timer(int connfd,struct sockaddr_int client_address);//创建新定时器
void adjust_timer(utile_timer *timer);//调整定时器时间
void deal_timer(utile_timer *timer,int sockfd);//处理超时连接
public:
//基础
int m_port;
char *m_root;
int m_log_write;
int m_close_log;
int m_actormodel;
int m_pipefd[2];
int m_epollfd;
http_conn *users;
//数据库相关
connection_pool *m_connPool;
string m_user; //登录数据库用户名
string m_passWord; //登录数据库密码
string m_databaseName; //登录数据库名
int m_sql_num;
//线程池相关
threadpool<http_conn> *m_pool;
int m_thread_num;
//epoll_event相关
epoll_event events[MAX_EVENT_NUMBER];
int m_listenfd;
int m_OPT_LINGER;
int m_TRIGMode;
int m_LISTENTrigmode;
int m_CONNTrigmode;
//定时器相关
client_data *users_timer;
Utils_utils;
};
#endif
WebServer.cpp具体实现
构造函数
WebServer::WebServer()
{
//http_conn类对象
users=new http_conn[MAX_FD];
//root文件夹路径
//获取当前工作目录(系统调用)
char server_path[200];
//getcwd()会将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数size为buf的空间大小
getcwd(server_path,200);
//构造根目录路径
char root[6]="/root";
m_root = (char *)malloc(strlen(server_path)_strlen(root)+1);//标准库内存分配
strcpy(m_root,server_path);
strcpy(m_root,root);
//client_data是自定义的定时器客户端数据结构
users_timer = new client_data[MAX_FD];//创建定时器数据数组
}
析构函数
WebServer::~WebServer()
{
//关闭文件描述符
close(m_epollfd);
close(m_listenfd);
close(m_pipefd[1]);
close(m_pipefd[0]);
//自定义部分
//释放动态分配的内存
delete[] users;//释放HTTP链接对象数组(自定义类型)
delete[] users_time;//释放定时器数据数组(自定义类型)
delete m_pool;//释放线程池对象(自定义模板类)
}
概念回顾
套接字(socket)的概念
- 在网络通信过程中,需要创建一个信息的载体来进行数据的通信,这个载体我们可以称之为套接字
- 我们可以调用函数:socket(),创建一个用于通信的套接字端点,并返回该端点对应的文件描述符
- 在通信端点中,有两个缓冲区,分别对应发送缓冲区和接受缓冲区
- 原理图

基于TCP面向连接的通信方式
在网络通信过程中,有两种通信方式,分别是基于BS模型的,即浏览器服务器模型,和基于CS模型,即客户端服务器模型,本次项目用的是基于BS模型,但下面是CS模型
- 通信原理图

TCP并发服务器
- 循环服务器的模型
点击查看代码
sfd = socket(); //创建用于链接的套接字文件描述符
bind(); //绑定ip地址和端口号
listen(); //启动被动监听状态
while(1)
{
newfd = accept(); //阻塞接受客户端连接请求
//跟客户端进行数据收发
recv();
send();
close(newfd);
}
close(sfd);
- accept函数和recv函数都是阻塞函数,但是,我们想让这两个阻塞任务同时执行,互不相干扰,此时,我们就要引入并发机制:多进程、多线程、IO多路复用

浙公网安备 33010602011771号