OPRE-HTTP-Server
OPRE逻辑结构
OPRE为了提高client连接处理速度,将响应端口请求与数据接收发送给线程池,然后继续查询是否有端口请求,而线程池接收到响应控制参数及socket值后会唤醒一个闲置的进程处理该client的数据接受及数据响应。
线程池结构
线程池主要包括线程池创建,线程方法,线程挂起,线程唤醒,任务分配,线程池销毁及线程控制结构,线程池结构。
//线程控制结构体
typedef struct pthread_control_struct
{
//线程id
pthread_t p_ptid;
//线程信息互斥锁
pthread_mutex_t p_mutex;
//线程消息
pthread_cond_t p_cond;
//线程当前状态 0为挂起 1为运行 2为标示退出 3为线程死亡
short p_state;
}pthread_ctrl_t;
//线程参数结构体
typedef struct pthread_member_task
{
//该线程控制程序
pthread_ctrl_t *m_ptid;
//线程执行参数
//线程执行的socket
int m_socketid;
//socket控制信息
int *m_sockctrl;
//任务状态信息
int *m_isintask;
//主目录路径
char *m_dirpath;
}pthread_mtask_t;
//线程池结构体
typedef struct pthread_pool_struct
{
//线程控制数组指针
pthread_ctrl_t *o_ptpool;
//线程参数数组指针
pthread_mtask_t *o_ptmem;
//线程池中线程总数目
int o_ptsum;
//设置访问阻塞
pthread_mutex_t mutex;
}pthread_pool_t;
相应客户端处理
select、close线程与主线程共享同一个client连接处理结构体,主要控制服务器所处理的所有数据。设置一个结构体原因主要是方便数据管理与精简的参数传递。
//client连接处理结构体
typedef struct server_socekt_deal_struct
{
//主文件夹路径
char *d_dirpath;
//客户端最大数量
int d_maxlink;
//客户端当前数量
int d_curlink;
//客户端序列表
int *d_clisok;
//客户端连接信息 0为连接断开 1为连接中
int *d_lstate;
//客户端任务执行状态 0为未执行任务 1为正在执行
int *d_task;
//客户端可连接位置
int d_liloc;
//客户端连接时间 超时关闭用
long *d_linktime;
//连接超时时长
int d_otime;
//select用的数据
int d_maxsoc;
fd_set d_fds;
struct timeval d_timeout;
//线程池
pthread_pool_t *d_pool;
//线程状态相关信息
pthread_ctrl_t *d_ctrl;
//select线程条数
int d_selsum;
}server_sds_t;
一、并发select线程
服务器存在多个select线程,每个线程处理不同的socket区块,设置select控制结构体用于区分线程所处理socket区块。
//select线程控制结构体
typedef struct SelectCtrlStr
{
//控制结构
server_sds_t *s_sds;
//线程select号
int s_selectid;
}select_ctrl;
二、端口无连接关闭线程
端口关闭并设置端口控制标记
//端口号
sds->d_clisok[i]=-1;
//连接时间
sds->d_linktime[i]=0;
//连接状态
sds->d_lstate[i]=0;
//任务状态
sds->d_task[i]=0;
//连接数量
--sds->d_curlink;
并发客户端请求处理
一个线程只处理一个客户端请求,并响应该请求。
//线程参数结构体
typedef struct pthread_member_task
{
//该线程控制程序
pthread_ctrl_t *m_ptid;
//线程执行参数
//线程执行的socket
int m_socketid;
//socket控制信息
int *m_sockctrl;
//任务状态信息
int *m_isintask;
//主目录路径
char *m_dirpath;
}pthread_mtask_t;
http数据解析
目前OPRE更多关注主体架构,目前只允许静态页面与各类型文件传输请求,目前OPRE将http请求数据解析存储与请求数据结构体中。并且由于业务逻辑的独立性,在请求响应可以根据自己需求修改,可加入gzip压缩模块,php解析模块,由于服务器处于多线程中,不支持CGI,但可以扩展为以socket通讯的cgi方式。
//http请求值
typedef struct HTTPREENV
{
//请求方法
char REQUEST_METHOD[8];
//如果是get存get值最大是1024
char QUERY_STRING[1025];
//如果是post自行开辟空间
char *POST_STRING;
//post数据长度
char CONTENT_LENGTH[16];
//用户信息
char USER_AGENT[256];
//http请求类型 content-type 类型传输
char HTTP_ACCEPT[256];
//用户请求文件路径
char REQUEST_PATH[256];
//连接类型 keep-alive close
char CONNECT_TYPE[32];
//http协议
char HTTP_PCTL[16];
//Accept-Encoding gzip类型压缩的东西
char ACCEPT_ENCODE[256];
}httpenv_t;
//文件缓存结构体
typedef struct FILESEND
{
char *fbuff;
int fsize;
}fsend_t;
opre服务器配置
OPRE配置文件支持#注释
#最大客户端连接数
linksum = 100
#客户端链接存活时间
existtime = 6
#最多同时处理客户端数目
clientsum = 10
#服务器监听ip地址
lishost = 192.168.11.122
#服务器监听端口号
lisport = 8081
#目录的路径(.为当前目录)
homepath = ./inside
github
相关工程代码会上传到github
写在最后
由于在开发OPRE过程中发现select的种种问题,近期会用epoll重写,并将会服务器与响应端彻底分开,以便支持分布式环境,如此服务器相当与一个转发端,将数据接接收后发往一个或多个不同的响应端,响应端数据处理后向服务器提交数据后再由服务器转发。以此来提高服务器并发量,以及实现一个服务器便可管理多个网站。