一个简单的wed服务器SHTTPD(3)————SHTTPD多客户端支持的实现
//start from the very beginning,and to create greatness
//@author: Chuangwei Lin
//@E-mail:979951191@qq.com
//@brief: SHTTPD多客户端支持的实现
#include "lcw_shttpd.h"
static int workersnum = 0;//工作线程的数量
extern struct conf_opts conf_para;
pthread_mutex_t thread_init = PTHREAD_MUTEX_INITIALIZER;//这里就已经初始化了互斥锁
int WORKER_ISSTATUS(int status);
static struct worker_ctl *wctls = NULL;//线程选项
void Worker_Init();
int Worker_Add(int i);
void Worker_Delete(int i);
void Worker_Destory();
/******************************************************
函数名:do_work(struct worker_ctl *wctl)
参数:控制结构
功能:执行任务
*******************************************************/
static void do_work(struct worker_ctl *wctl)
{
DBGPRINT("LCW==>do_work\n");
struct timeval tv; //超时时间
fd_set rfds; //读文件集
int fd = wctl->conn.cs;//客户端的套接字描述符
struct vec *req = &wctl->conn.con_req.req;//请求缓冲区向量
int retval = 1;//返回值
for(;retval > 0;)
{
FD_ZERO(&rfds); //清读文件集
FD_SET(fd, &rfds);//将客户端连接描述符放入读文件集
//设置超时
tv.tv_sec = 300;//conf_para.TimeOut;
tv.tv_usec = 0;
//超时读数据
retval = select(fd + 1, &rfds, NULL, NULL, &tv);
switch(retval)
{
case -1://错误
close(fd);
break;
case 0://超时
close(fd);
break;
default:
printf("select retval:%d\n",retval);
if(FD_ISSET(fd, &rfds))//检测文件
{
memset(wctl->conn.dreq, 0, sizeof(wctl->conn.dreq));
//读取客户端数据
req->len = read(wctl->conn.cs, wctl->conn.dreq, sizeof(wctl->conn.dreq));
req->ptr = wctl->conn.dreq;
DBGPRINT("Read %d bytes,'%s'\n",req->len,req->ptr);
if(req->len > 0)
{
//分析客户端的数据
wctl->conn.con_req.err = Request_Parse(wctl);//待实现
//处理并响应客户端请求
Request_Handle(wctl);//待实现
}
else
{
close(fd);
retval = -1;
}
}
}
}
DBGPRINT("LCW<==do_work\n");
}
/******************************************************
函数名:worker(void *arg)
参数:worker_ctl *wctls
功能:线程处理函数
*******************************************************/
static void* worker(void *arg)
{
DBGPRINT("LCW==>worker\n");
struct worker_ctl *ctl = (struct worker_ctl *)arg;//为何不直接传这个类型过来?
struct worker_opts *self_opts = &ctl->opts;//定义一个选项结构
pthread_mutex_unlock(&thread_init);//解锁互斥
self_opts->flags = WORKER_IDEL;//初始化线程为空闲,等待任务
//如果主控线程没有让此线程退出,则循环处理任务
for(;self_opts->flags != WORKER_DETACHING;)//while(self_opts->flags != WORKER_DETACHING)
{
//DBGPRINT("work:%d,status:%d\n",(int)self_opts->th,self_opts->flags );
//查看是否有任务分配
int err = pthread_mutex_trylock(&self_opts->mutex);//互斥预锁定
//pthread_mutex_trylock()是pthread_mutex_lock() 的非阻塞版本
if(err)
{
//DBGPRINT("NOT LOCK\n");
sleep(1);
continue;
}
else
{
//有任务,do it
DBGPRINT("Do task\n");
self_opts->flags = WORKER_RUNNING;//执行标志
do_work(ctl);
close(ctl->conn.cs);//关闭套接字
ctl->conn.cs = -1;
if(self_opts->flags == WORKER_DETACHING)
break;
else
self_opts->flags = WORKER_IDEL;
}
}
//主控发送退出命令
//设置状态为已卸载
self_opts->flags = WORKER_DETACHED;
workersnum--;//工作线程-1
DBGPRINT("LCW<==worker\n");
return NULL;
}
/******************************************************
函数名:WORKER_ISSTATUS(int status)
参数:欲查询的线程状态
功能:查询线程状态
*******************************************************/
int WORKER_ISSTATUS(int status)
{
int i = 0;
for(i = 0; i<conf_para.MaxClient;i++)
{
if(wctls[i].opts.flags == status)
return i;//返回符合的线程
}
return -1;//没有符合的线程状态
}
/*****************************************************
函数名:Worker_Init()
参数:无
功能:初始化线程
******************************************************/
void Worker_Init()
{
DBGPRINT("LCW==>Worker_Init");
int i = 0;
//初始化总控参数
wctls = (struct worker_ctl*)malloc( sizeof(struct worker_ctl)*conf_para.MaxClient);//开辟空间
memset(wctls,0, sizeof(*wctls)*conf_para.MaxClient);//清零
//初始化一些参数
for(i=0;i<conf_para.MaxClient;i++)
{
//opt&connn结构和worker_ctl结构形成回指针
wctls[i].opts.work = &wctls[i];
wctls[i].conn.work = &wctls[i];
//opts结构部分的初始化
wctls[i].opts.flags = WORKER_DETACHED;
//wctls[i].opts.mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init(&wctls[i].opts.mutex,NULL);//初始化互斥锁
pthread_mutex_lock(&wctls[i].opts.mutex);
//conn部分的初始化
//con_req&con_res与conn结构形成回指
wctls[i].conn.con_req.conn = &wctls[i].conn;
wctls[i].conn.con_res.conn = &wctls[i].conn;
wctls[i].conn.cs = -1;//客户端socket连接为空
//conn.con_req部分初始化:请求结构
wctls[i].conn.con_req.req.ptr = wctls[i].conn.dreq;
wctls[i].conn.con_req.head = wctls[i].conn.dreq;
wctls[i].conn.con_req.uri = wctls[i].conn.dreq;
//conn.con_res部分初始化:响应结构
wctls[i].conn.con_res.fd = -1;
wctls[i].conn.con_res.res.ptr = wctls[i].conn.dres;
}
for (i = 0; i < conf_para.InitClient;i++)
{
//增加规定个数工作线程
Worker_Add(i);
}
DBGPRINT("LCW<==Worker_Init\n");
}
/******************************************************
函数名:Worker_Add(int i)
参数:
功能:增加线程
*******************************************************/
int Worker_Add(int i)
{
DBGPRINT("LCW==>Worker_Add\n");
pthread_t th;//线程参数
int err = -1;//返回值
if (wctls[i].opts.flags == WORKER_RUNNING)
{
return 1;//如果线程已经在工作,则返回
}
pthread_mutex_lock(&thread_init);//进入互斥区(之前有初始化过了)
wctls[i].opts.flags = WORKER_INITED;//状态为已初始化
err = pthread_create(&th, NULL, worker, (void*)&wctls[i]);//建立线程
//线程处理函数为worker
pthread_mutex_unlock(&thread_init);//解锁互斥
//更新线程选项
wctls[i].opts.th = th;//线程ID
workersnum++;//线程数量增加1
DBGPRINT("LCW<==Worker_Add\n");
return 0;
}
/******************************************************
函数名:Worker_Delete(int i)
参数:线程序号
功能:减少线程
*******************************************************/
void Worker_Delete(int i)
{
DBGPRINT("LCW==>Worker_Delete\n");
wctls[i].opts.flags = WORKER_DETACHING;//线程状态改为正在卸载
DBGPRINT("LCW<==Worker_Delete\n");
}
/******************************************************
函数名:Worker_Destory()
参数:
功能:销毁线程
*******************************************************/
void Worker_Destory()
{
DBGPRINT("LCW==>Worker_Destory\n");
int i = 0;
int clean = 0;
for(i=0;i<conf_para.MaxClient;i++)
{
DBGPRINT("thread %d,status %d\n",i,wctls[i].opts.flags );
if(wctls[i].opts.flags != WORKER_DETACHED)//如果状态不是已经卸载
Worker_Delete(i);
}
while(!clean)
{
clean = 1;
for(i = 0; i<conf_para.MaxClient;i++)
{
DBGPRINT("thread %d,status %d\n",i,wctls[i].opts.flags );
if(wctls[i].opts.flags == WORKER_RUNNING || wctls[i].opts.flags == WORKER_DETACHING)
clean = 0;
}
if(!clean)
sleep(1);
}
DBGPRINT("LCW<==Worker_Destory\n");
}
//定义调度状态
#define STATUS_RUNNING 1
#define STATSU_STOP 0
static int SCHEDULESTATUS = STATUS_RUNNING;
/******************************************************
函数名:Worker_ScheduleRun(int ss)
参数:文件描述符
功能:当有客户端连接到来的时候,将客户端连接分配给空闲客户端,由客户端处理到来的请求
*******************************************************/
int Worker_ScheduleRun(int ss)
{
DBGPRINT("LCW==>Worker_ScheduleRun!!!\n");
struct sockaddr_in client;
socklen_t len = sizeof(client);
//初始化线程服务
Worker_Init();
int i = 0;
for(;SCHEDULESTATUS== STATUS_RUNNING;)
{
struct timeval tv;//超时时间
fd_set rfds;//读文件集
//printf("SCHEDULESTATUS:%d\n",SCHEDULESTATUS);
int retval = -1;//返回值
FD_ZERO(&rfds); //清读文件集,将客户端连接
FD_SET(ss, &rfds);//描述符放入读文件集
//设置超时
tv.tv_sec = 0;
tv.tv_usec = 500000;
//超时读数据
retval = select(ss + 1, &rfds, NULL, NULL, &tv);
switch(retval)
{
case -1://错误
case 0://超时
continue;
break;
default:
if(FD_ISSET(ss, &rfds))//检测文件
{
int sc = accept(ss, (struct sockaddr*)&client, &len);
printf("client comming\n");//接受请求
i = WORKER_ISSTATUS(WORKER_IDEL);//查找空闲业务处理线程
if(i == -1)
{
i = WORKER_ISSTATUS(WORKER_DETACHED);//没有找到
if(i != -1)
Worker_Add(i);//增加一个业务处理线程
}
if(i != -1)//业务处理线程空闲,分配任务
{
wctls[i].conn.cs = sc;//套接字描述符
pthread_mutex_unlock(&wctls[i].opts.mutex);//告诉业务线程有任务
}
}
}
}
DBGPRINT("LCW<==Worker_ScheduleRun\n");
return 0;
}
/******************************************************
函数名:Worker_ScheduleStop()
参数:
功能:停止调度过程
*******************************************************/
int Worker_ScheduleStop()
{
DBGPRINT("LCW==>Worker_ScheduleStop\n");
SCHEDULESTATUS = STATSU_STOP;//给任务分配线程设置终止条件
int i =0;
Worker_Destory();//销毁业务线程
int allfired = 0;
for(;!allfired;)//查询并等待业务线程终止
{
allfired = 1;
for(i = 0; i<conf_para.MaxClient;i++)
{
int flags = wctls[i].opts.flags;
if(flags == WORKER_DETACHING || flags == WORKER_IDEL)//线程正活动
allfired = 0;
}
}
pthread_mutex_destroy(&thread_init);//销毁互斥变量
for(i = 0; i<conf_para.MaxClient;i++)
pthread_mutex_destroy(&wctls[i].opts.mutex);//销毁业务吃力线程的互斥
free(wctls);//销毁业务数据
DBGPRINT("LCW<==Worker_ScheduleStop\n");
return 0;
}
一个简单的wed服务器SHTTPD(3)————SHTTPD多客户端支持的实现的更多相关文章
- 一个简单的wed服务器SHTTPD(9)————main函数文件,Makefile,头文件
主函数: #include "lcw_shttpd.h" //初始化时服务器的默认配置 extern struct conf_opts conf_para= { "/us ...
- 一个简单的wed服务器SHTTPD(1)————命令行和文件配置解析
开始学习<LInux网络编程>中的综合案例,虽然代码书上有,还是自己打一下加深理解和印象. 主要有两个函数,完成命令行的解析,另一个实现配置文件的解析,注释还是比较丰富的哦. //star ...
- 一个简单的wed服务器SHTTPD(6)———— SHTTPD错误处理的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(5)————服务器SHTTPD请求方法解析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(4)————SHTTPD支持CGI的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(7)———— SHTTPD内容类型的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(8)———— URI分析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(2)———— 客户端请求分析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 自己动手模拟开发一个简单的Web服务器
开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的W ...
随机推荐
- Django 已生成数据时怎么查询数据库
数据库已写好时,怎样查询数据库 1.输入命令:python manage.py inspectdb > model1.py 注:>重定向 到model1.py
- dubbo(三):负载均衡实现解析
dubbo作为分布式远程调用框架,要保证的点很多,比如:服务注册与发现.故障转移.高性能通信.负载均衡等等! 负载均衡的目的是为了特定场景下,能够将请求合理地平分到各服务实例上,以便发挥所有机器的叠加 ...
- AI vs PS 矢量 VS 位图
矢量图 AI最大可以放大64000%.不会失真,依然很清晰.原理是不同的点以及点与点之间的路径构成的,不论放大的多大,点在路径在,就可以精确的计算出它的区域.AI中无法直接编辑位图. 位图 代表PS, ...
- Mybatis源码详解系列(三)--从Mapper接口开始看Mybatis的执行逻辑
简介 Mybatis 是一个持久层框架,它对 JDBC 进行了高级封装,使我们的代码中不会出现任何的 JDBC 代码,另外,它还通过 xml 或注解的方式将 sql 从 DAO/Repository ...
- mongodb的远程连接和配置(阿里ECS)
1.) 首先安装mongodb 2.)配置mongodb.conf bind_ip = 0.0.0.0 port= dbpath=/root/mongodb/mongodb-linux-x86_64- ...
- python3_learn 实现文件夹内批量对图片重命名
初衷 练习Python,提高动手能力. 珍藏的壁纸文件夹名命有点乱. 可以学习下一些基础的库 开始(.jpg,无筛选) First 首先找到OS库,寻找可以遍历文件名的.找到了OS.walk() os ...
- python爬取优美图库海量图片,附加代码,一键爬取
优美高清图片为大家提供高清美女套图赏析,非高清不录入,大家的网速要给力. 今天教大家爬取优美图库网站中高质量的图片!! 简单易上手哦~ 使用工具: Python 3.6 pycharm 相关环境: r ...
- 小白初学Java的一点点收获
作为刚刚学习Java没有几天的小白,我想把我在学习过程中,所学习到的知识和注意事项和大家一起分享分享.在这个过程中,希望大家可以有所收获,有什么不对的地方,希望大家指出并且私信我. 首先说说第一次记事 ...
- Java 网络编程 -- 基于TCP 实现聊天室 群聊 私聊
分析: 聊天室需要多个客户端和一个服务端. 服务端负责转发消息. 客户端可以发送消息.接收消息. 消息分类: 群聊消息:发送除自己外所有人 私聊消息:只发送@的人 系统消息:根据情况分只发送个人和其他 ...
- 网络找的 关于 “中吹” Janus Dongye
看了这篇文章,感觉错过了一个精彩的人生. Janus Dongye, Coding Peasant at Universityof Cambridge (2012-present)(剑桥码农,2012 ...