JAWS模块分析(小东子)
前言:学习ACE也已经有半年了,虽然还很肤浅,但感觉有那么一点意思了。最近分析了一下JAWS模块,拿出来跟大家共通交流。欢迎大家的讨论。杜绝商业目的,并保持文章的完整性。
本人信箱:yuanjiandong512@163.com
一  JAWS模块概况
总则:
JAWS主要有四个主要分块:并发策略(线程池、每个申请一个线程、单线程),I/O策略(同步,反应式,异步方式),协议处理(管道方式,模块方式),文件系统(LRU,LFU)。
   JAWS主要的设计模式,单体模式,抽象工厂模式,工厂方法模式,反应器模式,主动对象模式,流水线模式,服务器运行时配置方式等)
   JAWS的架构如图1-1所示:(总体方案)

图1-1  JAWS Web服务器构架
JAWS的并发策略如图1-2所示:

图1-2  JAWS 并发策略(线程池、Thread-per-Request)
JAWS的I/O策略如图1-3所示:

图1-3  JAWS I/O策略(同步策略、反应式、异步方式)
JAWS的协议流水线策略如图1-4所示:

图1-4  JAWS协议流水线策略
JAWS的文件缓存策略如图1-5所示:

图1-5  JAWS文件缓存策略
二 JAWS1程序分析
一 概述
   JAWS1的程序实现没有完成全部JAWS的设计思想,主要进行了并发策略、I/O策略的完成。设计结构跟JAWS2比较,没有JAWS2的面向对象结构化强,没有它封装的好。
二 程序流程
第一阶段:MAIN()到数据库的INIT()
1、main() -> ACE_Service_Config.open()(采用运行时配置模式,svc.conf文件配置)加载生成的动态库(此处采用ACE自己的生产动态库的方式,参考书1,p24)(本分析采用默认选项:线程池,同步I/O)
2、http_server::init(),分析参数,根据参数选择并发策略(同步线程池、异步线程池、PER-REQUEST),生成工厂处理方法(Synch_HTTP_Handler_Factory ()、No_Cache_Synch_HTTP_Handler_Factory ())。
3、http_server::init()生成并发策略,调用http_server ->synch_thread_pool()。
4、http_server ->synch_thread_pool()开始侦听,HTTP_Server ->acceptor_.open()。
注意:不管采用什么并发策略都在server调用自己的函数生成并发策略时在自己的函数里面执行了端口侦听,也就是说open()由HTTP_Server完成。
5、http_server ->synch_thread_pool()构建线程池对象,Synch_Thread_Pool_Task t(),并把acceptor_的引用传递过来。然后等待所有的线程退出,ACE_Thread_Manager:tm_.wait (),程序进入循环等待状态。
6、Synch_Thread_Pool_Task的构造函数Synch_Thread_Pool_Task->activate()产生多个线程开始从SVC()开始执行。
注意:多个线程共用一个主动对象,共用一个消息队列,有同一个ACE_Thread_Manager:tm_进行管理,但每个线程有自己的堆。根据需要,可以设计自己的专有线程存储。
第二阶段:线程的SVC()
1、线程进入死循环
2、创建一个ACE_SOCK_Stream stream,然后this->acceptor_.accept (stream)。
注意这里使用的acceptor_是一个加锁的接收器,也就是多个线程在这里等待,仅有一个线程获取锁继续执行。因为线程池共用一个主动对象,所以也共用一个acceptor_,所以必须采用并发策略。采用同一个acceptor_,可以确保在同一个I/O端口上连接,这也是WEB服务器必须要求的。
3、第一步的2步骤生成的工厂Synch_HTTP_Handler_Factory .create_http_handler (),创建一个处理器。(在JAWS2中没有采用这个方法,由于它的面向对象做的更完美,都是通过JAWS_DATA_BLOCK块在流水线中执行完成的,不同的流水线模块完成不同的功能)
4、处理器开始处理到来的客户连接,handler->open (stream.get_handle (), *mb)。
第三阶段:处理器处理客户连接
1、根据需要对SOCK进行了一些设置,通过ACE_OS::setsockopt()。
2、设置接收流为acceptor_.accept (stream)函数连接的stream。
3、调用this->read_complete(),开始接收数据,并开始了一序列的处理。
注意:JAWS1中并没有采用流水线设计模式,但留出了接口虚函数。
4、主要读取客户申请头,并分析,HTTP_REQUEST.CPP,根据分析的头向客户回复HTTP_RESPONSE.CPP。
第四阶段:读取客户发来的数据,分析协议,并进行回复。(本人没有进行仔细分析,本人认为没有采用文件缓存策略)
注:其它并发方式和I/O方式代替响应的方式就可以了,流程没有大的变化,就是具体实现思想有点改变。
三 JAWS2程序分析
一 概述
   JAWS2采用了更多的面向对象封装,增加了流水线处理(但跟书1上讲的实现方式不一样,它采用一个循环,不断的往下一下流模块中压入JAWS_DATA_BLOCK,通过改变JAWS_DATA_BLOCK中内容而改变需要完成的任务,而书1上讲的更制式一点)和文件缓存系统。

主要有4块内容设计:
1、JAWS_Dispatch_Policy(抽象工作模式)定义了:并发策略(Thread Pool Task和Thread Per Task)处理器工厂(生成响应的IO处理方式,采用了工厂方法模式)IO接收器(IO Acceptor的方式:Synch、Asynch)IO流接收方法(IO Stream)。
 
2、JAWS_IO_Handler
 
3、JAWS_Data_Block(最重要的数据块,主要通过它在流模块中的传递,实现各个流模块的具体功能)
 
4、JAWS pipeline Handler,流水线,具体的accept(),stream(),文件的传输都在里面实现(具体参加见参考1)
 
二 程序流程
第一阶段:main()->数据库的init(),在JAWS2源代码中没有实现main(),而仅仅有动态库的源代码。
1、根据配置文件或命令行参数完成dispatch policy结构的初始化(并发策略:policy_.concurrency(),I/O策略:policy_.io(),acceptor策略:policy_.acceptor(),工厂策略:policy_.ioh_factory())
注意:在JAWS2中更多的采用面向对象结构设计,上面的并发策略都采用单体模式设计。
2、并发策略调用make(),JAWS_Thread_Pool_Singleton::instance ()->make();make函数完成线程池的创建,activate();各个线程进入SVC(),并阻塞在getq (mb)调用上。
注意:在JAWS_Concurrency_Base::singleton_mb()中使用了一个小技巧,在这里使用了“守卫锁”实现并发,只有获取锁的线程才能够阻塞在getq (mb)调用上,而其它线程阻塞在“守卫锁”上。但这个程序就只往消息队列里面压了一个JAWS Data Block数据块,阻塞在getq (mb)上的线程获取以后,消息队列里面就没有了,其它线程就不能够获取这个数据块了,而这个数据块是驱动线程能够继续执行下去的条件。在源代码中,采用编程技巧,但阻塞在getq (mb)上的线程获取JAWS Data Block数据块后,把变量mb_acquired_=1,但其它阻塞在“守卫锁”上的线程获取锁后,首先判断这个mb_acquired变量,如果等于1,则不进行getq (mb)调用,而是直接把第一个线程获取的JAWS Data Block数据块返回。
3、acceptor策略开始open(),policy_.acceptor ()->open (inet_addr)。
注意:I/O策略并没有开始accept(),这些都在流水线中完成,通过向主动对象的队列压入数据块,唤醒阻塞的线程,然后线程调用流水线完成accept,客户的申请,客户的应答。
问题:在JAWS2源码中这时候init()就结束了,没有提供到JAWS_Server::open()的调用,而JAWS_Server::open()中才完成policy_.acceptor ()->accept ()。经过查资料,也没有找到在动态加载中默认调用open()方法,有兴趣的可以查一查资料,有没有这个默认调用,发我信箱共同讨论研究。本人现认为,要不在init()中包含到JAWS_Server::open()的调用,要不在main()中包含到JAWS_Server::open()的调用。
第二阶段:JAWS_Server::open()开始执行,完成ACCEPT,客户申请,客户应答等。
1、构建一个JAWS Data Block数据块,有三个变量:JAWS IO Handler(IO处理器)初始化为0,在accept接收以后,才通过象JAWS1那样的Factory工厂创建,并更改JAWS Data Block数据块中这个变量的值;JAWS Dispatch Policy(包含第一阶段初始化的4个策略方式),初始化为第一阶段生成的Policy对象。JAWS Pipeline Handler(管道处理器),初始化为管道的第一个模块JAWS_Pipeline_Accept_Task_Singleton)
注意:1、管道里面有很多模块,第一个模块完成accept接收,第二个模块到倒数第二个模块完成客户的申请,客户应答等,最后一个模块完成事后处理,把动态生成的对象释放等处理。
注意:2、程序在开始把数据块的指针指向第一个模块,处理完第一个模块后,又把数据块的指针指向第二个模块,由于在线程的SVC函数中执行了一个死循环,所以通过改变JAWS Data Block数据块中JAWS Pipeline Handler的参数,实现调用不同的模块完成不同的任务。(跟书1描述的流水线实现有区别,本人认为书1描述的实现方式结构化更好一点,更容易理解)
  2、把JAWS Data Block数据块压入主动对象的消息队列,激活阻塞在上面的等待线程,policy->concurrency ()->put (db)。
3、程序进行等待所有的线程退出,ACE_Thread_Manager::instance ()->wait (),主程序结束。
第三阶段:线程从消息队列里面取出数据块进行处理
1、所有线程都从消息队列里面返回一个JAWS Data Block数据块。
2、SVC函数调用svc_loop函数,这是个死循环。主要调用svc_hook函数完成具体的功能。然后自己完成JAWS Data Block数据块中参数的变化,使再一次循环过来,svc_hook函数能够根据改变后的JAWS Data Block数据块中参数执行。
3、从线程池里面取出一个等待线程完成流水线的任务,在这里采用了线程池的半同步/半异步模型。(这一点没有仔细研究,有兴趣的可以仔细分析,通过JAWS_Waiter实现的)
4、把数据块压入JAWS Pipeline Handler模块,task->put (mb)。
第四阶段:模块开始根据消息块进行处理
1、put函数调用handle_put(),然后把消息块的task_指针改为下一模块,具体工作handle_put()完成。
2、第一个模块的handle_put()函数完成accept(),JAWS_IO *io = policy->io (),io->accept (handler)。然后退出,交给下一个模块进行处理。
注意:这里有好几个循环,本人没有仔细分析各个具体循环的用处,循环的主要目的是实现各个模块,完成流的功能,使用多个循环可能是具体管理上的编程技巧。

四JAWS3程序分析
书1:ACE程序员指南——网络与系统编程的实用设计模式
参考1:jaws 2: Refactorization Framework Design and Utilizatin Overview

JAWS模块分析(小东子)相关推荐

  1. 旅游类APP-Android模块分析

    2.Android模块分析 2.1系统框架 2.2Android APP启动流程 AndroidManifest.xml 2.3网络交互 2.4开发中的知识点 1.启动时使用引导页使用渐变效果: pr ...

  2. Android GNSS 模块分析(四)HAL 层

    紧接着上一篇(Android GNSS 模块分析(三)JNI 层),继续来分析下 Android GNSS HAL 层的功能,本篇准备先介绍下 HIDL 层的封装.至于后面的 HAL 层的功能,由于使 ...

  3. BetaFlight模块设计之二十:CMS菜单模块分析

    BetaFlight模块设计之二十:CMS菜单模块分析 CMS菜单模块 CMS菜单按键控制 CMS菜单Elements CMS_Menu OSD_Etnry Element类型 可调Element类型 ...

  4. dpdk-16.04 igb_uio 模块分析

    igb_uio 是 dpdk 内部实现的将网卡映射到用户态的内核模块,它是 uio 模块的一个实例. igb_uio 是一种 pci 驱动,将网卡绑定到 igb_uio 隔离了网卡的内核驱动,同时 i ...

  5. Nginx upstream模块与负载均衡模块分析

    目录 Upstream模块介绍 总体实现流程| memcached模块分析 负载均衡模块 正文 系列文章:upstream demo_fdsafwagdagadg6576的专栏-CSDN博客 本文是对 ...

  6. 觉SLAM的主要功能模块分析

    视觉SLAM的主要功能模块分析 一.基本概念 SLAM (simultaneous localization and mapping),也称为CML (Concurrent Mapping and L ...

  7. Asterisk cli模块分析

    最近写一些工具库,需要远程命令行调试(cli)功能,原有的一个cli模块是将接收处理的命令具体实现在cli模块中,其他模块需要修改添加自己的cli命令都需要去修改cli模块代码,觉得模块间耦合度太高, ...

  8. 2016年大数据Spark“蘑菇云”行动代码学习之AdClickedStreamingStats模块分析

    2016年大数据Spark"蘑菇云"行动代码学习之AdClickedStreamingStats模块分析     系统背景:用户使用终端设备(IPAD.手机.浏览器)等登录系统,系 ...

  9. 来自damon的zencart二次开发教程-2.2登录模块分析

    我们在制作zencart的模板时,经常会遇到需要将zencart的登陆页面与注册账户页面分离的情况(在 默认情况下,点击"Login"按钮会进入登陆页面与注册账号页面,登录zenc ...

  10. live555 源码分析:子会话 SDP 行生成

    如我们在前文 live555 源码分析:ServerMediaSession 中看到的,H264VideoFileServerMediaSubsession 的继承层次体系如下图: 在这个继承层次体系 ...

最新文章

  1. 车道检测源码分析系列
  2. 106. 动态中位数【经典 / 对顶堆】
  3. 查看是否由两个单词组成
  4. 计算机任务驱动法教学应用,任务驱动教学法在计算机教学中的应用
  5. 如何在IE地址栏显示自己的小图标
  6. 语法之知识点的改进(Func/Action)
  7. 初学JSP+Servlet常见的错误
  8. JfreeChart中文文档
  9. 1036 和奥巴马一起学编程
  10. 商业流程中的traversedpath
  11. 基于QT的超市信息管理系统
  12. 过流媒体取流失败_海康硬盘录像机:监控点取流失败,开始重连.错误代码为iVMS-4200.EXE[302]求大神解决...
  13. 第一次实习面试感受----苦逼程序员生活初体验
  14. JixiPix Portrait Painter for mac(照片转油画工具)
  15. RNN、self-attention、transform的浅显或许错误的理解
  16. 微信小程序模板-分页滑动栏
  17. 【附源码】计算机毕业设计JAVA医院病历管理系统
  18. CFileDialog控件ID值
  19. 2014中国计量学院matlab考试卷,中国计量学院学习心得
  20. 【AD20学习笔记】PCB设计规则设置及手工布线

热门文章

  1. js一键复制并调起微信客户端
  2. 数据库范式的经典例题,what are you 弄啥嘞?
  3. Js 中null 和underfined的区别
  4. 求出二维数组的最大元素及其所在的坐标
  5. 【计算机毕业设计】外卖点餐源码
  6. 计算机word基础操作知识,word文档基本操作
  7. 计算机操作系统存在的意义,电脑操作系统的作用
  8. PySide6官方教程 循序渐进学好Qt for Python
  9. 嵌入式软件未来发展趋势
  10. WordPress采集插件推荐都是免费采集插件