【网络编程】Web服务器shttpd源码剖析——线程池调度

 

hello !大家好呀! 欢迎大家来到我的网络编程系列之web服务器shttpd源码剖析——线程池调度,在这篇文章中,你将会学习到在Linux内核中如何创建一个自己的并发服务器shttpd,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!!

希望这篇文章能对你有所帮助,大家要是觉得我写的不错的话,那就点点免费的小爱心吧!

               

目录

​一.多线程池作用

​1.1 SHTTPD的多客户支持需求

​1.2 SHTTPD多线程池的实现

​二.多线程状态及其函数

 ​2.1 多线程状态

 ​2.2 多线程创建以及销毁


一.多线程池作用

1.1 SHTTPD的多客户支持需求

SHTTPD支持多个客户端的并发连接,在同一时刻允许多个客户同时成功获得服务器上的网络资源,这是现代服务器的基本属性,SHTTPD启动的时候处理单元初始化了多个线程,当客户增加超过上限时候,会根据现场情况增加处理单元。

 如图:

 当超过四个客户端并发访问时,SHTTPD会将后来的请求放在队列排序中,当处理单元空闲时再响应其他请求。

1.2 SHTTPD多线程池的实现

服务器SHTTPD的多客户端支持模块为此程序的主处理模块。在此模块中进行客户端连接的处理、请求数据的接收、响应数据的发送和服务线程的调度。模块的核心部分采用线程池的服务器模型,如图:

 模块初始化的时候,建立线程池,其中的线程负责接收客户端的请求、解析数据并响应数据。当客户端请求到来的时候,主线程查看当前线程池中是否有空闲的工作线程,当没有工作线程的时候会建立新的工作线程,然后分配任务给空闲的线程。

工作线程轮询接收客户端的请求数据,进行请求数据分析并响应请求,处理完毕后,关闭客户端的连接,等待主线程分发下一个请求。

 多客户端模块的线程处理框架如图所示:

主要分为两个部分:线程调度部分和线程退出部分。线程调度部分负责线程初始化、线程的增减、线程的销毁及线程互斥区的保护。线程退出部分则发送信号给工作线程,使得工作线程能够及时地释放资源。这主要应用于接收到用户的信号 SIGINT 时调用。
 

二.多线程状态及其函数

 2.1 多线程状态

工作线程分为多个状态:初始化状态 , 线程空闲状态, 线程运行状态 , 线程退出中状态和线程退出完毕状态:

线程建立的时候状态为线程初始化状态,此时工作线程不可以接受主线程的任务,刚刚进入线程函数。

线程建立完毕的时候进入线程空闲状态,此时可以接受主线程分配的任务,处理客户端的请求,并进行响应。

线程运行状态为线程正在处理客户端请求的时机,可以由空闲状态转入,转入的条件为主线程分配给此线程一个任务。

在处理完客户端请求时,线程可以转入空闲状态,等待下一次客户端请求任务的分配。

线程退出中的状态主要由接收到SIGINT 信号后调用线程退出函数时引起,此时各个线程在非阻塞的时候会及时响应此状态,释放资源、关闭连接。进入线程退出。

进入退出状态后各个线程都释放完申请的动态资源。

 2.2 多线程创建以及销毁

线程控制管理结构:

struct worker_opts{pthread_t th;            //线程的ID号int flags;                //线程状态pthread_mutex_t mutex;//线程任务互斥struct worker_ctl *work;//本线程的总控结构
};

之后使用线程初始化函数,将所有线程初始化:

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(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 itDBGPRINT("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;elseself_opts->flags = WORKER_IDEL;}}//主控发送退出命令//设置状态为已卸载self_opts->flags = WORKER_DETACHED;workersnum--;//工作线程-1DBGPRINT("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_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");
}

当然,这只是一部分源码,但这些是最主要的线程池框架,许多小的细节函数大家可以自己实现或者查资料,找我也是可以的哦!(欢迎私信!!!) 

   好啦!到这里这篇文章就结束啦,关于实例代码中我写了很多注释,如果大家还有不懂得,可以评论区或者私信我都可以哦!! 感谢大家的阅读,我还会持续创造网络编程相关内容的,记得点点小爱心和关注哟!   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/204.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FebHost:注册.CA域名的企业有什么限制?

在加拿大&#xff0c;只要满足加拿大互联网注册管理局的“加拿大注册要求”&#xff0c;任何类型的企业都可以注册.CA域名。这些要求的目的是为了确保.CA域名空间作为一个重要的公共资源得到合理的使用和开发&#xff0c;以促进所有加拿大人的社会和经济发展。 以下是一些主要…

docker安装EelasticSearch、目录权限修改、并安装IK 中文分词器

文章目录 docker安装EelasticSearch、目录权限修改、并安装IK 中文分词器1、docker安装ES2、docker ps发现容器没有正常启动&#xff0c;docker logs 容器id 查看日志发现是挂载目录的权限不足3、修改目录的权限4、使用docker restart 容器id重新启动刚才没有启动成功的容器5、…

Leetcode 4.18

Leetcode 1.无重复字符的最长子串2.最长回文子串3.整数反转4.字符串转换整数 (atoi)5.正则表达式匹配 1.无重复字符的最长子串 无重复字符的最长子串 滑动窗口&#xff0c;先让右指针右移&#xff0c;如果发现这个子串有元素和右指针当前元素重复。 则&#xff1a; 左指针右移…

【嵌入式之中断】

Cortex-M4集成了嵌套式矢量型中断控制器(Nested Vectored Interrupt Controller (NVIC))来实现高效的异常和中断处理。NVIC实现了低延迟的异常和中断处理&#xff0c;以及电源管理控制。它和内核是紧密耦合的。 凡是打断程序顺序执行的事件都称为异常&#xff08;exception&am…

极狐GitLab x LigaAI,AI 时代研发提效新范式

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 近日&#xff0c;极狐GitLab 和 LigaAI 宣布合作&#xff0c;双…

CentOS 7安装Zookeeper

说明&#xff1a;本文介绍如何在CentOS 7操作系统下使用Zookeeper 下载安装 首先&#xff0c;去官网下载所需要安装的版本&#xff0c;我这里下载3.4.9版本&#xff1b; 上传到云服务器上&#xff0c;解压 tar -xvf zookeeper-3.4.9.tar.gz修改配置 进入Zookeeper目录下的co…

【技术变现之道】如何打造IT行业的超级个体?

前言 在当今的数字化时代&#xff0c;IT行业蓬勃发展&#xff0c;为具备技术专长的个人提供了无限的可能性。想要成为IT行业的超级个体&#xff0c;实现知识与技能的变现吗&#xff1f;以下是一些高效途径&#xff0c;助你一臂之力&#xff01; 1. 独立接单外包 1&#xff09…

vue3数字滚动组件

效果图 一、安装插件 npm i vue3-count-to 二、components文件夹下新建BaseCountTo.vue文件 <template><BaseCountTo :endVal"endVal" :decimals"decimals" /> </template> <script setup > import { defineComponent, watch, r…

改手机IP地址的软件推荐

随着移动互联网的普及&#xff0c;手机已成为人们日常生活中不可或缺的一部分。而在使用手机的过程中&#xff0c;IP地址作为一个重要的网络标识&#xff0c;有时也需要进行修改或更改。为了满足这一需求&#xff0c;市面上涌现出了许多改手机IP地址的软件。虎观代理将对这些软…

韩顺平Java | C27 正则表达式

入门介绍 需求&#xff1a;提取文本中某类字符 传统方法&#xff1a;遍历每个字符&#xff0c;判断其是否在ASCII码中某种类型得编码范围内&#xff0c;代码量大&#xff0c;效率不高 正则表达式(RegExp, regular expression)&#xff1a;处理文本的利器&#xff0c;是对字符…

java混淆的公司有哪些

一些提供 Java 混淆服务的公司包括&#xff1a; PreEmptive Solutions&#xff1a;PreEmptive Solutions 提供了一系列用于保护 Java 和 .NET 应用程序的工具&#xff0c;包括混淆、代码压缩、加密和漏洞检测等功能。 DexGuard&#xff1a;DexGuard 是 Guardsquare 公司推出的…

【JavaWeb】异步请求——AJAX

目录 Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;优点传统Web与Ajax的差异Ajax工作流程Ajax 经典应用场景XMLHttpRequest常用方法事件常用属性 ajax: GET请求和POST请求的区别 传统Ajax实现传统方式实现Ajax的不足 $.ajax()语法常用属性参数常用函数参数 Aja…

golang 迷宫回溯算法(递归)

// Author sunwenbo // 2024/4/14 20:13 package mainimport "fmt"// 编程一个函数&#xff0c;完成老鼠找出路 // myMap *[8][7]int 地图&#xff0c;保证是同一个地图&#xff0c;因此是引用类型 // i,j表示对地图的哪个点进行测试 func SetWay(myMap *[8][7]int, …

网络基础-基于TCP协议的Socket通讯

一、Socket通讯基于TCP协议流程图 UDP 的 Socket 编程相对简单些不在介绍。 二、 服务端程序启动 服务端程序要先跑起来&#xff0c;然后等待客户端的连接和数据。 服务端程序首先调用 socket() 函数&#xff0c;创建网络协议为 IPv4&#xff0c;以及传输协议为 TCP 的…

基于XML配置bean(二)

文章目录 1.工厂中获取bean1.静态工厂1.MyStaticFactory.java2.beans.xml3.测试 2.实例工厂1.MyInstanceFactory.java2.beans.xml3.测试 3.FactoryBean&#xff08;重点&#xff09;1.MyFactoryBean.java2.beans.xml3.测试 2.bean配置信息重用继承抽象bean1.beans.xml2.测试 3.…

HarmonyOS实战开发-如何实现一个简单的健康生活应用

功能概述 成就页面展示用户可以获取的所有勋章&#xff0c;当用户满足一定的条件时&#xff0c;将点亮本页面对应的勋章&#xff0c;没有得到的成就勋章处于熄灭状态。共有六种勋章&#xff0c;当用户连续完成任务打卡3天、7天、30天、50天、73天、99天时&#xff0c;可以获得…

SpringBoot框架——8.MybatisPlus常见用法(常用注解+内置方法+分页查询)

1.MybatisPlus常用注解&#xff1a; 1.1 当数据库、表名和字段名和实体类完全一致时无需加注解&#xff0c;不一致时&#xff1a; TableName指定库名 TableId指定表名 TableField指定字段名 1.2 自增主键&#xff1a; TableId(typeIdType.AUTO) private Long id; 1.3 实体类中属…

2000-2022年各省人力资本水平数据(含原始数据+计算过程+计算结果)(无缺失)

2000-2022年各省人力资本水平数据&#xff08;含原始数据计算过程计算结果&#xff09; 1、时间&#xff1a;2000-2022年 2、来源&#xff1a;国家统计局 3、指标&#xff1a;普通高等学校在校学生数(万人)、年末常住人口&#xff08;万人&#xff09;、人力资本水平 4、范…

CTFshow-PWN-前置基础(pwn20)

提交ctfshow{【.got表与.got.plt是否可写(可写为1&#xff0c;不可写为0)】,【.got的地址】,【.got.plt的地址】 前置基础知识&#xff1a; .got 和 .got.plt 是 ELF&#xff08;Executable and Linkable Format&#xff0c;可执行和可链接格式&#xff09;二进制文件中的两个…

(四)qt中使用ffmpeg播放视频,可暂停恢复

一、在qt中添加ffmpeg库及头文件 INCLUDEPATH /usr/local/ffmpeg/include LIBS -L/usr/local/lib -lavutil -lavcodec -lavformat -lswscale 二、详细代码 FFempegVideoDecode 视频解码类&#xff08;放入线程中&#xff09; ffmpegvideodecode.h #ifndef FFMPEGVIDEODE…