BOA架构资料.docx

上传人:b****2 文档编号:13917373 上传时间:2023-06-19 格式:DOCX 页数:59 大小:41.85KB
下载 相关 举报
BOA架构资料.docx_第1页
第1页 / 共59页
BOA架构资料.docx_第2页
第2页 / 共59页
BOA架构资料.docx_第3页
第3页 / 共59页
BOA架构资料.docx_第4页
第4页 / 共59页
BOA架构资料.docx_第5页
第5页 / 共59页
BOA架构资料.docx_第6页
第6页 / 共59页
BOA架构资料.docx_第7页
第7页 / 共59页
BOA架构资料.docx_第8页
第8页 / 共59页
BOA架构资料.docx_第9页
第9页 / 共59页
BOA架构资料.docx_第10页
第10页 / 共59页
BOA架构资料.docx_第11页
第11页 / 共59页
BOA架构资料.docx_第12页
第12页 / 共59页
BOA架构资料.docx_第13页
第13页 / 共59页
BOA架构资料.docx_第14页
第14页 / 共59页
BOA架构资料.docx_第15页
第15页 / 共59页
BOA架构资料.docx_第16页
第16页 / 共59页
BOA架构资料.docx_第17页
第17页 / 共59页
BOA架构资料.docx_第18页
第18页 / 共59页
BOA架构资料.docx_第19页
第19页 / 共59页
BOA架构资料.docx_第20页
第20页 / 共59页
亲,该文档总共59页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

BOA架构资料.docx

《BOA架构资料.docx》由会员分享,可在线阅读,更多相关《BOA架构资料.docx(59页珍藏版)》请在冰点文库上搜索。

BOA架构资料.docx

BOA架构资料

针对当前MTK WEB机制进行代码分析总结,总体来说当前机制的重点及难点涉及两个部分,一个是请求处理的核心状态机变迁过程,另一个就是ASP动态解析器的实现,这里分为三部分进行描述,分别对核心状态机变迁、ASP词法解析、语法解析、语法树动作的总结,以及当前服务器的源码分析笔记。

 

一、核心状态机变迁

 

二、词法解析、语法解析、语法树动作。

这部分算是当前WEB服务器比较难的一块,如果理解了这部分的实现机制,基本上理解当前WEB服务器的代码也就没有什么障碍了,鉴于个人对编译原理也并不了解,这部分也不太容易详细的解释,这里会涉及很大一部分lex、yacc(或GNU flex、GNU bison)工具的使用以及它们的语法编写,所以偷懒一下,仅仅分析针对我们当前项目,利用这些工具及语法文件为我们生成了什么东西,如果对这些机制感兴趣,可以自学这块的技术,再结合当前分析结果,会对WEB服务器整套机制有更清晰的认识。

 

1、基本原理

a、当用户通过浏览器访问WEB服务器,此时WEB服务器通过请求URL了解到用户希望浏览的页面文件名(假设是test.asp),WEB服务器通过文件扩展名知道了用户在请求一个ASP类型的文件,WEB服务器在本地找到该文件并打开,调用语法解析器。

b、语法解析器的实现代码在我们当前项目中是使用yacc(或GNU bison)工具生成,当然前提是需要一个根据当前语法需求编写的一个特定yacc语法文件(比如当前项目为grammar.y),语法解析器的输入对象除了需要yacc语法文件外,还需要调用词法解析器,通常词法解析器可以使用lex(或GNU flex)生成,但当前项目并没有使用lex,而是自己用C代码写了一个词法解析器(gb-lex.c)供语法解析器使用。

c、WEB服务器调用语法解析器时,语法解析器不断调用词法解析器获取标记及标记值,词法解析器通过读取请求URL指定的ASP文件进行分析,找出符合条件的标记及标记值,并提供给语法解析器使用,语法解析器在根据之前用户提供的语法描述进行语法归约,同时对每一个匹配的语法项执行对应的语法动作,这些语法动作创建了一棵关联的语法树。

d、当WEB服务器调用语法解析器完成之后,语法树也就相应的生成了(当前项目生成的语法树保存在do_asp函数的内部变量中reent->root),之后WEB服务器通过对语法树执行指定的处理来完成轻量级的ASP语言解析执行(通常lex、yacc仅仅完成语法树的生成,具体针对语法树的使用需要看当前是做什么目的,比如当前项目是实现解释型语言编译器,即完成ASP语法到C语法的转换及运行)。

 

2、词法解析

通常词法解析都是借用lex(或GNU flex)工具,及lex词法文件来完成,但目前MTK方案没有借用lex工具,而是自己实现了词法解析器,感兴趣的同事可以通过gb-lex.c文件来了解MTK词法解析器的实现,由于之前也提到语法解析器需要词法解析器获取解析出来的标记及标记值,所以gb-lex.c文件中实现的函数、变量、枚举值有一大部分并不是随意写的,这些值有些是引用语法解析器中的定义,有些需要提供给语法解析器调用(比如当前语法解析器程序需要调用词法解析器程序gb_lex名称的函数来进行核心词法解析, 而当词法解析器解析到当前内容是GB_HTML_BLOCK标记时,又需要将该标记值的内容传给语法解析器指定的yyval->v_text中),具体细节需要感兴趣的同事自行学习lex、yacc相关的技术知识,才能理解他们之间的关系引用,这里不进行详细描述。

这里总结一下当前MTK词法解析器生成的解析结果:

是否在ASP语法标记内(*)

标记

描述

GB_IF

解析asp文件内容为“If”部分。

(不区分大小写)

GB_ELSE

解析asp文件内容为“Else”部分。

(不区分大小写)

GB_ELSEIF

解析asp文件内容为“ElseIf”部分。

(不区分大小写)

GB_END

解析asp文件内容为“End”部分。

(不区分大小写)

GB_THEN

解析asp文件内容为“Then”部分。

(不区分大小写)

GB_SCRIPT

解析asp文件内容为“@SCRIPT”部分,通过对yacc语法文件生成的语法树及对应的语法树动作了解到这部分功能没有实现。

GB_STRING

解析asp文件内容包含在双引号中的内容。

=

解析asp文件内容为“=”部分,通过对yacc语法文件分析了解到目前该标记仅用于条件判断是否相等的比较使用,并不能做为赋值符号来使用。

<

解析asp文件内容为“<”部分,通过对yacc语法文件分析了解到,该标记必须和“>”一起使用,用于条件判断是否不等的比较使用,如“1 <> 2”,但并不能做为小于的比较使用,当前语法文件没有实现小于的判断功能。

>

同“<”描述相同。

解析asp文件内容为“(”部分,通过对yacc语法文件分析了解到,该标记必须和“)”一起使用,则表示对内部私有定义的函数调用,同时当前语法文件中固定死了函数的参数为0~3个,参数之间使用逗号分隔。

如“tcwebApi_get("VoIPBasic_Common","VoIPLine2Enable","h")”。

同“(”描述相同。

解析asp文件内容为“,”部分,通过yacc语法文件分析了解到,该标记仅用于函数的参数分隔使用。

GB_ID

这个表示当前解析的内容在ASP语法标记内(即表示是在<% %>内),但以上那些标记都不匹配,这部分内容则标记为GB_ID。

比如“<%tcwebApi_get(a,b,c)%>”,这个例子含有4个GB_ID,分别为tcwebApi_get、a、b、c

GB_HTML_BLOCK

读取ASP文件,不包含在ASP语法标记内的部分都归为该标记,通过对语法树动作了解到这部分内容会原封不动地发给浏览器客户端

* 是否在ASP语法标记内:

我们以前学习ASP语言知道,ASP的语句在web页面文件中通常是包含在<%  %>中,同样在词法解析器中,也根据这个原则来进行词法分析,如果读取的输入内容没有在<%  %>中,则表示是普通的HTML、js等等其它原静态WEB内容,否则如果读取的输入内容在<% %>中,则内部的词法解析需要按ASP语言的实现来进行对待。

3、语法解析

通常语法解析都是借用yacc(或GNU bison)工具,及yacc语法文件来完成,当前MTK方案的实现也是采用这个方法,当前MTK方案的yacc语法文件为grammar.y。

由于yacc语法文件的编写不是一两句话就可以描述清楚,建议感兴趣的同事自行学习lex、yacc相关的技术知识,这里不进行详细描述,仅针对当前MTK方案的语法文件描述进行总结。

 

//aspfile为语法分析的起点,aspfile代表一个完整的支持asp格式的文件内容语法描述

//一个ASP文件内容语法是由声明语句组构成。

aspfile -> statements

 

//声明语句组 是由多个声明语句构成,注意这里使用了递归嵌套。

statements -> statement

         -> statements statement

 

//每个声明语句可以表示为以下4种类型的任意1种。

//1、@SCRIPT xxx = “xxx”,通过分析语法树动作了解到,即使通过语法解析器解析成功,

//但最终执行代码没有实现。

//2、不包含在ASP语法标记内的部分,详见“词法解析”中的描述。

//3、一条普通语句(见后面stmt的描述)

//4、判断语句(见后面cond的描述)

statement -> GB_SCRIPT GB_ID '=' GB_STRING

        -> GB_HTML_BLOCK

        -> stmt

        -> cond

 

//一条普通语句 可以表示为一条函数调用语句,或者一个标签语句。

stmt -> stmt_call

-> val

 

//一条函数调用语句,这里语法文件固定死了,当前私有函数只能支持0~3个参数。

stmt_call -> GB_ID '('')'

        -> GB_ID '(' GB_STRING ')'

        -> GB_ID '(' GB_STRING ',' GB_STRING ')'

        -> GB_ID '(' GB_STRING ',' GB_STRING ',' GB_STRING ')'

 

//标签语句,由以下任意一种表示

//1、GB_STRING 这个比较好理解,像<%”xxx”%>中的xxx就是这种类型

//2、GB_ID 在语法文件中有两处地方使用,一处是在stmt_call中用来表示私有函数名

//   那么另一种情况比较特殊,如<%hello%>,通过分析语法树动作了解到,这种情况

//   是被忽略的,不做任何处理。

val -> GB_STRING

   -> GB_ID

 

//判断语句,当前语法描述可以构成如下3种判断语句

//1、一条逻辑分支的判断语句

If 条件 Then

声明语句组

End If

//2、二条逻辑分支的判断语句

If 条件 Then

声明语句组

Else

声明语句组

End If

//3、多条逻辑分支的判断语句

If 条件 Then

声明语句组

ElseIf 条件 Then

声明语句组

ElseIf 条件 Then

    声明语句组

End If

 

cond -> cond_list GB_END GB_IF

    -> cond_list cond_else GB_END GB_IF

 

cond_list -> GB_IF stmt_cond GB_THEN statements

        -> cond_list GB_ELSEIF stmt_cond GB_THEN statements

cond_else -> GB_ELSE statements

 

//条件判断语句,目前只支持等于和不等于两种判断条件,通过对语法树动作分析了解到

//当前条件判断的实现只支持字符串的比较,所以等于和不等于已经可以满足此需求。

stmt_cond -> stmt '=' stmt

         -> stmt '<' '>' stmt

4、语法树动作

在yacc语法文件中,通常在语法描述的旁边编写了针对当前语法描述的执行动作,最终目地是为了生成一个语法树,以提供给当前程序使用,用于实现某种功能,比如当前项目会使用生成的语法树实现一种用于动态页面的轻量级ASP语言解释器)。

 

如果要弄明白语法树的生成,需要了解yacc相关的技术知识,感兴趣的同事可以自行学习这方面的技术,这里仅针对目前项目构成的语法树动作做一个总结。

 

在do_asp函数中,首先调用语法解析器gb_parse (reent)进行当前asp文件的语法解析,之后解析器会将生成的语法树存储于reent->root中,再调用run_stmts (reent, reent->root)来根据语法树完成轻量级ASP语言解释器的功能实现。

语法树动作标识

描述

AST_HTML

该动作标识表明当前的内容是属于非ASP语法的内容,针对这部分内容直接发送给远端的浏览器。

比如Hello这种非ASP语法的内容,不需要进行ASP解释处理,直接发给远端。

AST_CALL

该动作标识是用来处理如下ASP私有函数,当前方案支持11种ASP私有函数(asp_Write、request_Form、tcWebApi_Set、tcWebApi_Get、tcWebApi_Unset、tcWebApi_Commit、tcWebApi_Save、tcWebApi_CurrentDefaultRoute、tcWebApi_constSet、tcWebApi_staticGet、tcWebApi_CommitWithoutSave),这些函数的实现都比较简单,这里就不在详细描述。

 

<%tcwebApi_get(a,b,c)%>

AST_CALL_ID

残留代码,在语法文件中已经废弃,不再支持。

AST_CALL_ID_1

残留代码,在语法文件中已经废弃,不再支持。

AST_ID

目前该动作标识没有处理,直接忽略,这种动作标识是由<%xxx%>这种格式生成,没有什么意义。

AST_STRING

该动作标识表示当前是一个字符串,目前在该项目中通常用于条件比较。

如<%If tcwebApi_get(a,b,c) = “yyy” Then ......%>,这里的“yyy”对应当前语法树动作,仅仅将字符串原样返回。

AST_NULL

目前该动作标识没有处理,直接忽略,这种动作标识是由<%@SCRIPT xxx = “xxx”%>这种格式生成,目前没有实现该功能。

AST_COND

该动作标识表明当前语法树节点是一个判断处理,这部分比较复杂,在下面用语法树来描述判断处理,相信再结合代码就会比较容易理解了。

判断处理的语法树:

1、一条逻辑分支的判断语句

If 左比较标识 操作符 右比较标识 Then 

    声明语句组 

End If

 

2、二条逻辑分支的判断语句

If 左比较标识 操作符 右比较标识 Then

声明语句组1

Else

    声明语句组2

EndIf

 

3、多条逻辑分支的判断语句

If 左比较标识1 操作符1 右比较标识1 Then

声明语句组1

ElseIf 左比较标识2 操作符2 右比较标识2 Then

声明语句组2

Then

    声明语句组3

End If

三、源码分析笔记

[cpp]viewplaincopyprint?

1.//主程序  

2.main  

3.//初始化支持的ASP私有函数处理链表,链表头为asp_funcs,后续语法解析器解析  

4.//出<%xxx(x,y,z)%>格式的语法标记后,会使用xxx与当前私有函数处理链表中的条  

5.//目进行比较,找出当前支持的ASP私有函数,并调用当前函数指针进行处理。

  

6.    init_asp_funcs ();  

7.  

8.//生成WEB页面映射表,这里一定要和WEB HTML框架上的页面文件名称统一,  

9.//当浏览器发出Http请求后,会使用请求URL的请求路径与当前这个WEB页面映射  

10.//表的页面文件名进行匹配。

  

11.//当前该映射表采用了如下格式,其中pageMap数组的外部索引对应HTML框架中主  

12.//菜单个数,pageMap数组的内部索引对应HTML框架中指定主菜单下涉及的子菜单  

13.//个数,这里的next指针相当于在子菜单下又级联二级子菜单,但当前方案并没使用  

14.//二级子菜单。

  

15.//pageMap[1][1]->page_name = "sta-device.asp";  

16.//pageMap[1][3]->next = NULL;  

17.init_pageMap();  

18.  

19.//更切当前程序的根目录,当前程序是通过程序参数传入,目前设置为根目录为  

20.//“/boaroot”  

21.fixup_server_root();  

22.  

23.    //从/boaroot/boa.conf文件中读取配置信息,这里使用了lex/yacc技术机制。

  

24.read_config_files();  

25.  

26.//建立非阻塞型的套接口,用于处理http请求,当前监听端口为tcp 80,允许最大的  

27.//连接数为250  

28.server_s = create_server_socket();  

29.  

30.//初始化信号处理  

31.init_signals();  

32.  

33.//用户权限降低,如果当前是root用户,则降低权限为配置文件中指定的用户等级、  

34.//用户组等级,当前配置文件也设置为0,所以这里没有意义。

  

35.drop_privs();  

36.  

37.//初始化通用环境变量,存储到common_cgi_env数组中,后续如果用户请求文件为  

38.//CGI类型,则需要通过私有环境变量机制将主程序的信息传送给CGI程序。

  

39.create_common_env();  

40.  

41.//初始化是否需要字符转义的位图表,这里使用了位图算法来存储哪些字符需要转义  

42.//,哪些字符不需要转义。

  

43.build_needs_escape();  

44.  

45.//涉及定时器比较的旧值存储使用  

46.initTimerStruct();  

47.  

48.//获取最大能创建的套接口数  

49.c = getrlimit(RLIMIT_NOFILE, &rl);  

50.max_connections = rl.rlim_cur;  

51.  

52.//创建守护进程,当前进程退出,留下子进程。

  

53.if (do_fork)  

54.    switch(fork())  

55.    case -1:

  

56.        exit

(1);  

57.        break;  

58.    case 0:

  

59.        break;  

60.    default:

  

61.        exit(0);  

62.        break;  

63.  

64.status.requests = 0;  

65.status.errors = 0;  

66.start_time = current_time;  

67.  

68.//核心主循环处理,下面单独分析。

  

69.select_loop(server_s);  

70.  

71.//释放之前用于页面映射的资源  

72.free_pageMap();  

73.  

74.----------------------------------------------------------------------------------------------------------------------  

75.//boa的主循环处理  

76.select_loop  

77.    //当前ka_timeout值从配置文件中读取,当前为10秒  

78.req_timeout.tv_sec = (ka_timeout ?

 ka_timeout :

 REQUEST_TIMEOUT);  

79.req_timeout.tv_usec = 0l;  

80.max_fd = -1;  

81.  

82.while 

(1)  

83.    //收到SIGHUP信号,并进行处理,该信号主要用于重新加载配置文件  

84.    if (sighup_flag)  

85.        sighup_run();  

86.  

87.    //收到SIGCHLD信号,进行子进程控制块资源回收  

88.        if (sigchld_flag)  

89.            sigchld_run();  

90.  

91.        //收到SIGALRM信号,打印mime_hashtable、passwd_hashtable两个hash表的  

92.        //条目个数。

  

93.        if (sigalrm_flag)  

94.            sigalrm_run();  

95.  

96.        //收到SIGTERM信号,当前处理方式为将TCP 80监听的套接口从block_read_fdset  

97.        //中移除,同时关闭该套接口。

  

98.        if (sigterm_flag)  

99.            if (sigterm_flag == 1)  

100.                sigterm_stage1_run(server_s);  

101.  

102.            if (sigterm_flag == 2 && !

request_ready && !

request_block)  

103.                sigterm_stage2_run();  

104.  

105.        max_fd = -1;  

106.  

107.        //检查到有阻塞的请求控制块,则更新阻塞请求控制块的相关信息。

  

108.        //在fdset_update函数内部通常分两个阶段处理:

  

109.        //1、首先将当前请求控制块的文件描述符放入select监听事件集中,在当前这次主  

110.        //循环不会进行任何处理,但由于已经将需要文件描述符放入select监听事件集中,  

111.        //所以在下一轮处理中,如果select引擎检测到当前要监听的事件,则送快速的再  

112.        //次进入主循环来再调用fdset_update。

  

113.        //2、当再次调用fdset_update时,由于当前阻塞的请求控制块已经有了select监听  

114.        //事件,则走另外一个流程,该流程中将请求控制块从阻塞列表移入准备列表,并  

115.        //且将文件描述符从select监听事件集中去除,因为当前已经准备处理了。

之后在  

116.        //当前这轮主循环中检测到准备列表有请求控制块,则进行请求控制块的处理。

  

117.        if (request_block)  

118.            fdset_update();  

119.  

120.        //请求处理核心函数,该函数主要处理2件工作:

  

121.        //1、如果TCP 80监听的套接口检测到有远端的连接,则进行接入处理,同时生成  

122.        //请求控制块加入到准备列表中。

  

123.        //2、处理准备列表中的所有请求控制块,这里处理流程采用了有限状态机机制。

  

124.        //下面单独分析。

  

125.        process_requests(server_s);  

126.  

127.        //如果当前没有收到终止信号,并且当前TCP监听套接口的连接个数未达到上限,  

1

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2