ImageVerifierCode 换一换
格式:DOCX , 页数:12 ,大小:21.49KB ,
资源ID:6914320      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6914320.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(goaheadwebserver源码分析.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

goaheadwebserver源码分析.docx

1、goaheadwebserver源码分析1.一个txt文本架构图main() | |-websOpenServer() | |- websOpenListen() | |-socketOpenConnection() | |-打开webServer服务器 | |-初化socket_t结构(注册websAccept()回调函数(socket_t sp-accept= websAccept)等) | |-把socket_t结构加入数组socketList | | |-websUrlHandlerDefine() | |-初始化websUrlHandlerType结构的websUrlHandler数

2、组 | |-将urlPrefix和回调函数绑定在websUrlHandlerwebsUrlHandlerMax中 | |-websUrlHandlerDefine(websDefaultHandler) | |-初始化websUrlHandlerType结构的websUrlHandler数组 | |-将urlPrefix和回调函数绑定在websUrlHandlerwebsUrlHandlerMax中 | | | |-websFormDefine() | |-初始化symbol table结构sym_t,把名字和回调函数名放进sym_t结构 | |-把sym_t结构放进hash表中 | |-we

3、bsAspDefine() | |-初始化symbol table结构sym_t,把名字和回调函数名放进sym_t结构 | |-把sym_t结构放进hash表中 | | |(main loop) -|-socketReady(-1) | socketSelect(-1, 1000) |-轮询socketList |-轮询socketList中的handlerMask | | |-中的几个变量 |-改变socketList中的currentEvents | | | |-socketProcess() | |-轮询socketList | | |-socketReady() | | |-socke

4、tDoEvent() | | |-如果有新的连接(来自listenfd)就调用socketAccept() | | |-调用socketAlloc()初始化socket_t结构 | | |-把socket_t结构加入 socketList数组 | | |-调用socket_t sp-accept()回调函数 | | | | |-如果不是新的连接就查找socketList数组调用socket_t sp-handler()回调函数 | | | | -|websAccept() |-做一些检查 |-socketCreateHandler(sid, SOCKET_READABLE, websSocke

5、tEvent, (int) wp) | |-把sid注册为读事件,初始化socket_t sp-handler = websSocketEvent等, 更新对应的socketList数组(handlerMask值等) websSocketEvent() |-判断读写操作 |-读websReadEvent() | |-websUrlHandlerRequest() | |-查找wbsUrlHandler数组,调用和urlPrefix对应的回调函数(websFormHandler(),websDefaultHandler()等) | |-写,调用(wp-writeSocket)回调函数websFo

6、rmHandler() |-跟据formName查找hash表,调用用户定义的函数websDefaultHandler() |-处理默认的URL请求,包括asp页面 |-websSetRequestSocketHandler() | |-注册默认的写事件函数wp-writeSocket = websDefaultWriteEvent | |-socketCreateHandler(wp-sid, SOCKET_WRITABLE, websSocketEvent, (int) wp) | |-把sid注册为写事件,初始化socket_t sp-handler = websSocketEvent等

7、, 更新对应的socketList数组 websDefaultWriteEvent() |-写数据,不包括asp页面2.跟着main走Main函数很简短,所以可以对他的代码进行一行一行注释,如下:int main(int argc, char* argv)/* Initialize the memory allocator. Allow use of malloc and start * with a 60K heap. For each page request approx 8KB is allocated.* 60KB allows for several concurrent page

8、 requests. If more space* is required, malloc will be used for the overflow.*/*首先分配一个大的内存块(60*1024字节),以后只要是以b开头的对内存操作的函数都是在这个已经分好的内存块上的操作,这些操作在中实现。*/ bopen(NULL, (60 * 1024), B_USE_MALLOC);/*忽略SIGPIPE信号*/ signal(SIGPIPE, SIG_IGN);/* Initialize the web server初始化用户管理部分,打开web服务器,注册URL处理函数。用户管理部分在中实现,We

9、b服务器的初始化是在和中实现url处理函数在中实现*/ if (initWebs() handlerMask)注册给三个集合(读,写,例外),然后调用select系统调用,然后更新各个sock的sp-currentEvents,表示各个sock的当前状态。这两个函数在中实现,他们主要操作的数据是socket_t变量socketList中的handlerMask和currentEvents,socketList在中定义并主要由该文件中的socketAlloc,socketFree和socketPtr三个函数维护。*/if (socketReady(-1) | socketSelect(-1, 1

10、000) /*该函数处理具体的sock事件1,调用socketReady(sid)对socketListsid进行检查,看是否有sock事件2,如果有sock事件,则调用socketDoEvent()函数,对事件进行处理*/ socketProcess(-1); /*该函数在中实现,检查cgiRec变量cgilist,首先把cgi的结果输出,如果有的话,然后看cgi进程是否已对号束,如果结束,就清理该cgi进程。Cgilist在函数websCgiHandler和websCgiCleanup中维护。*/ websCgiCleanup();/*该函数在中实现,功能是检查sched_t变量sched

11、,断开超时的连接,sched变量在emfSchedCallback和emfUnschedCallback中维护*/ emfSchedProcess(); /*退出时的清理工作,永远不会执行到这里*/#ifdef WEBS_SSL_SUPPORT websSSLClose();#endif#ifdef USER_MANAGEMENT_SUPPORT umClose();#endif/* Close the socket module, report memory leaks and close the memory allocator*/ websCloseServer(); socketClo

12、se();#ifdef B_STATS memLeaks();#endif bclose(); return 0;3.一些想法1, 找出他们共同的数据结构2, 找出对这些数据结构维护(操作)的函数3, 从http的get或者是post流程来看程序4, 整体架构如何掌握5, 分模块,从全局的角度看各个模块的功能6, 从main函数起,按树型结构一层层分析下去选择第五种方法:1, sock模块,专门处理网络链接这一块,有这么几个文件:和,是(维护)处理链接的socket_t数据结构,是(维护)处理链接的。2, 对http协议数据进行操作(读取和分析),文件3, 对具体数据的操作(asp,form)

13、,文件选择第三种方法来看程序:假设有个http请求:从这个http请求到服务器的处理,然后返回这样一个过程来看goahead是怎么操作的1,写一个http请求的url和一个head1, 写一个http请求的post的head注:因为这次要看通整个goahead代码,所以一下子不知道以什么思路来看。上面是一些想法,不知道从哪里开始分析一个项目的代码,也不知道取舍哪些进行程序结构和功能方面的分析。后来的结果是写出了下面的文字。 mainloop源码分析 socketReady(-1)函数分析socketReady函数检查已建立连接的socket中是否有以下事件,如果检查到一个,就返回1,如果没有检

14、查到,就返回零。(1) sp-flags & SOCKET_CONNRESET,如果该socket的flag标志为SOCKET_CONNRESET(该标志在哪里设置(初始化)的),则调用函数socketCloseConnection(该函数后面会解释)关闭该socket连接,然后返回0;(2) sp-currentEvents & sp-handlerMask,如果该socket当前的事件和他要处理的事件相同,就返回1,告诉调用socketReady的函数有socket准备好被处理了;(3) sp-handlerMask & SOCKET_READABLE & socketInputBuffe

15、red(sid) 0,如果该socket要处理的事件是SOCKET_READABLE并且该socket的缓存中有可读的数据,则调用socketSelect函数(为什么在这里要调用这个函数,看了下socketSelect,应该是为了设置sp-currentEvents |= SOCKET_READABLE,所以这里应可以优化),然后返回1,告诉调用socketReady的函数有socket准备好被处理了;(4) socketReady函数根据传入的参数sid决定是检查id为sid的socket(当sid大于0),还是遍历整个socketList(当sid小于0),如果以上3个条件中没有一个满足,

16、则返回0。 socketSelect(-1, 1000)函数分析socketSelect函数是系统调用select的外包函数,该函数的主要功能就是监听()注册的socket事件集合,然后修改sp-currentEvents变量。流程如下:在主函数中,对socketSelect的调用是这样的:if (socketReady(-1) | socketSelect(-1, 1000),这样做并没有对socketSelect的返回值进行检查,也就是说当socketSelect返回-1时,该条件也会满足,从而程序也会往下走,所以,这个地方也是可以优化的。 socketProcess(-1)函数分析soc

17、ketProcess处理到达的socket事件,如果传入的参数是小于0,则会处理所有的socket的事件,如果大于0,则会处理指定的socket的事件。下面是主要过程:if (socketReady(sid) socketDoEvent(sp); socketReady()函数请看上面的解释,但不明白这里为什么还要用到这个函数,应该也是个可以优化的地方,我现在想到一个过程,应该是这样的:If(socketSelect ()/*If(socketReady() socketDoEvent();*/socketProcess();后注:走完websGetInput()函数的分析后,因为这时仔细看到

18、了更多的代码,上面的这个优化是不行的,因为socketReady(int sid)函数中,是sp-currentEvents,sp-handlerMask这几个标志位来判断是否有数据读写。socketDoEvent()是对已连接的socket通过改变sp-currentEvents和sp-handlerMask来分阶段的去处理数据,并不是一路执行到底直到把这个连接关闭的。socketSelect ()是主要还是用在有新连接到来的时候,有新连接到来才会使这个函数返回真。socketDoEvent大致分两个阶段去处理一个连接,1是READ阶段,READ处理成功,便会设置状态到WRITE阶段,却不执

19、行WRITE动作,2是WRITE阶段,WRITE执行完后才会结束这个连接。当第一次主循环时,socketDoEvent()执行的是READ,所以,如果按上一个代码段,第二次执行循环时,如socketSelect ()中没有新连接或数据到来,就不会往下执行了,而已有数据的连接将得不到立即的处理。socketReady(sid)可以检查已有连接是否有数据准备好读写,所以在这里优化是错误的。下面看看socketDoEvent函数的实现:(1)socketDoEvent函数首先对socket的当前事件进行检查,如果是读事件并且是服务器监听socket上的读事件,说明有新连接到来,于是调用socketA

20、ccept()欢迎新连接,并使currentEvents为0,然后马上返回。(2)如果当前不是读事件但是该socket原感兴趣的是读事件并且socket缓存中确有数据可读,那就置currentEvents为可读,这一步在socketReady函数中有做过,所以这里应该是可以去掉的。(3)如果当前是写事件,那就看看该socket的写缓存中有没有数据,如果有并且有SOCKET_FLUSHING标志就全部输出该写缓存,这是为新的写事件做清理工作。(4)调用事件处理函数sp-handler,该函数指针分别在两个地方进行初始化: 1,在websDefaultHandler()函数中注册写事件,该函数在什

21、么时候被调 2,在websAccept()函数中注册读事件 两处都指向websSocketEvent()函数。等下解释这个函数。(5)把currentEvents置为0。 socketAccept()函数分析socketAccept()函数接收一个新的连接,并且调用用户注册的接收函数,这一个过程后,就把对socket_t结构的处理转换到了webs_t结构。Sp-accept函数指针在socketOpenConnection()函数中调用socketAlloc()函数注册给监听socket的socket_t数据结构,当socketAccept()函数处理新连接时,就会把自已的Sp-accept指

22、针及其他几个属性通过调用socketAlloc(sp-host, sp-port, sp-accept, sp-flags)函数又给了新的连接,注意,调用完这个后,会更新新的nsp-flags &= SOCKET_LISTENING,把该连接和监听连接区别开。然后,监听socket用自已的Sp-accept调用到websAccept()函数,但是传递的第一个参数是新连接的id:nid。这也应该是个技巧吧。websAccept()函数功能:经过websAccept()函数后,将走出socket层,来到webs_t结构层,以后对读和写的操作都通过操作webs_t这个数据结构来完成。 websSoc

23、ketEvent()函数分析websSocketEvent()函数处理socket的读和写事件:(1)websSocketEvent()函数根据mask决定调用读还是写函数,wp-writeSocket函数指针在websDefaultHandler()中通过调用websSetRequestSocketHandler()进行注册,指向websDefaultWriteEvent()函数。(2)websReadEvent()函数:websReadEvent()函数处理读事件,我们怀疑这个函数有问题,会导致web服务器宕机,因此要重点分析。我们来看看该函数中用到的wp结构的四个状态:先给出一个http

24、的post头,看起来形象点:POST /goform/formTest HTTP/Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/, application/, application/msword, */*Referer: zh-cnContent-Type: application/x-www-form-urlencodedAccept-Encoding: gzip, deflateUser-Agent: Mozilla/ (com

25、patible; MSIE ; Windows NT ; SV1; .NET CLR CIBA)Host: 32Connection: Keep-AliveCache-Control: no-cachename=adfs&address=fdsafdsa&ok=OK(1)WEBS_BEGIN,该状态是在websAccept()函数调用wbesAlloc()函数初始化wp结构时被设置的,如果是在这个状态,该函数就调用websParseFirst()函数分析http头的第一行数据,在websParseFirst()中,主要会对wp结构的下面几个数据进行操作:wp-flags |= WEBS_POS

26、T_REQUEST;wp-query = bstrdup(B_L, query); wp-host = bstrdup(B_L, host); wp-path = bstrdup(B_L, path); wp-protocol = bstrdup(B_L, proto); wp-protoVersion = bstrdup(B_L, protoVer);对wp-flags几个重要的赋值:WEBS_CGI_REQUEST,WEBS_ASP,WEBS_LOCAL_PAGE等,分析好第一行后,调用ringqFlush()函数把wp-header做相当于清零的操作,把各个指针都指向这个缓冲的开始处。如

27、果websParseFirst()函数调用成功,就转到WEBS_HEADER状态:wp-state = WEBS_HEADER。按程序的流程,这个时候仍在循环中,马上就会转到WEBS_HEADER状态机,但是会这样吗(2)WEBS_HEADER,首先(1)以后(经过WEBS_BEGIN),除非websGetInput() ()函数调用不成功,否则就会执行到WEBS_HEADER状态机,这个时候我们就要看看websGetInput()函数了,因为这个函数如果调用不成功,是不会执行到WEBS_HEADER的。websGetInput()函数分析:函数功能:接收客户端的数据;函数返回值:-1,表示出

28、错或者请求已经被处理0, 表示告诉调用者还有更多的数据待读取1, 表示数据已经读好。websGetInput()函数的处理过程:注意上图中的两个注解,1是读取socket时,一次最多读256个字节,2是post的数据长度在websParseRequest(wp)函数中得到,也就是说如果一个连接首次调用websGetInput()函数,应该执行的是=0的那条分支。下面试着走一个流程,当websGetInput()函数接收上例post头时,会怎么处理。首先,程序会进入=0分支,接着会进入socketGets()函数,我们在这个函数里去走一圈:socketGets()函数从socket中读取一行,然

29、后返回,如现在读到的是:POST /goform/formTest HTTP/ 明显程序将直接走到ET CLR CIBA)Host: Keep-Alive程序不进入是因为wp-flags & WEBS_POST_REQUEST这个条件不成立,所以我给出上面的一个GET头,这时wp-flags中应该在WEBS_BEGIN状态机下的websParseFirst()函数中没有被设置为WEBS_POST_REQUEST,这里不得不插入一段websParseFirst()函数中的代码说明情况:if (gstrcmp(op, T(GET) != 0) if (gstrcmp(op, T(POST) = 0) wp-flags |= WEBS_POST_REQUEST; else if (gstrcmp(op, T(HEAD) = 0) wp-flags |= WEBS_HEAD_REQUEST; else websError(wp, 400, T(Bad request type); return -1; 看来,对于GET头,wp-flags并不需要设置一个WEBS_GET_XXX什么的标志位。原因说清了,按上图,程序

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1