goahead+webserver源码分析详细.docx

上传人:b****6 文档编号:8015534 上传时间:2023-01-28 格式:DOCX 页数:22 大小:179.60KB
下载 相关 举报
goahead+webserver源码分析详细.docx_第1页
第1页 / 共22页
goahead+webserver源码分析详细.docx_第2页
第2页 / 共22页
goahead+webserver源码分析详细.docx_第3页
第3页 / 共22页
goahead+webserver源码分析详细.docx_第4页
第4页 / 共22页
goahead+webserver源码分析详细.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

goahead+webserver源码分析详细.docx

《goahead+webserver源码分析详细.docx》由会员分享,可在线阅读,更多相关《goahead+webserver源码分析详细.docx(22页珍藏版)》请在冰豆网上搜索。

goahead+webserver源码分析详细.docx

goahead+webserver源码分析详细

转载goaheadwebserver源码分析

2011-03-1117:

40:

08|  分类:

工作|  标签:

|字号大中小 订阅

1.一个txt文本架构图

main()

     |

     |--websOpenServer()

     |            |--websOpenListen()

     |                          |--socketOpenConnection()

     |                                          |--打开webServer服务器

     |                                          |--初化socket_t结构(注册websAccept()回调函数(socket_tsp->accept=websAccept)等)

     |                                          |--把socket_t结构加入数组socketList

     |            

     |

     |--websUrlHandlerDefine()

     |               |--初始化websUrlHandlerType结构的websUrlHandler数组

     |               |--将urlPrefix和回调函数绑定在websUrlHandler[websUrlHandlerMax]中

     |

     |--websUrlHandlerDefine(websDefaultHandler)

     |               |--初始化websUrlHandlerType结构的websUrlHandler数组

     |               |--将urlPrefix和回调函数绑定在websUrlHandler[websUrlHandlerMax]中

     |         

     |

     |

     |--websFormDefine()

     |              |--初始化symboltable结构sym_t,把名字和回调函数名放进sym_t结构

     |              |--把sym_t结构放进hash表中

     |

     |--websAspDefine()

     |              |--初始化symboltable结构sym_t,把名字和回调函数名放进sym_t结构

     |              |--把sym_t结构放进hash表中

     |

     |

     |(mainloop)

  ----|--socketReady(-1)||socketSelect(-1,1000)

  ^                 |--轮询socketList       |--轮询socketList中的handlerMask

  | |               |--中的几个变量       |--改变socketList中的currentEvents

  | |

  | |--socketProcess()

  ^ |             |--轮询socketList[]

  | |              |--socketReady()

  | |              |--socketDoEvent()

  | |                               |--如果有新的连接(来自listenfd)就调用socketAccept()

  | |                                                   |--调用socketAlloc()初始化socket_t结构

  | |                                                   |--把socket_t结构加入socketList数组

  | |                                                   |--调用socket_tsp->accept()回调函数

  | |

  | |                               |--如果不是新的连接就查找socketList数组调用socket_tsp->handler()回调函数

  | |

  | |

  --|

 

websAccept()

    |--做一些检查

    |--socketCreateHandler(sid,SOCKET_READABLE,websSocketEvent,(int)wp)

    |           |--把sid注册为读事件,初始化socket_tsp->handler=websSocketEvent等,更新对应的socketList数组(handlerMask值等)

    

websSocketEvent()

    |--判断读写操作

    |--读websReadEvent()

    |               |--websUrlHandlerRequest()

    |                                    |--查找wbsUrlHandler数组,调用和urlPrefix对应的回调函数(websFormHandler(),websDefaultHandler()等)

    |

    |--写,调用(wp->writeSocket)回调函数

 

 

websFormHandler()

   |--跟据formName查找hash表,调用用户定义的函数

 

websDefaultHandler()

   |--处理默认的URL请求,包括asp页面

   |--websSetRequestSocketHandler()

   |                                             |--注册默认的写事件函数wp->writeSocket=websDefaultWriteEvent

   |                                             |--socketCreateHandler(wp->sid,SOCKET_WRITABLE,websSocketEvent,(int)wp)

   |                                                         |--把sid注册为写事件,初始化socket_tsp->handler=websSocketEvent等,更新对应的socketList数组

    

websDefaultWriteEvent()

   |

|--写数据,不包括asp页面

 

2.跟着main走

Main函数很简短,所以可以对他的代码进行一行一行注释,如下:

intmain(intargc,char**argv)

{

/*

 * Initializethememoryallocator.Allowuseofmallocandstart

 * witha60Kheap. Foreachpagerequestapprox8KBisallocated.

 * 60KBallowsforseveralconcurrentpagerequests. Ifmorespace

 * isrequired,mallocwillbeusedfortheoverflow.

 */

/*

首先分配一个大的内存块(60*1024字节),以后只要是以b开头的对内存操作的函数都是在这个已经分好的内存块上的操作,这些操作在Balloc.c中实现。

*/

   bopen(NULL,(60*1024),B_USE_MALLOC);

/*

忽略SIGPIPE信号

*/

   signal(SIGPIPE,SIG_IGN);

 

/*

 * Initializethewebserver

初始化用户管理部分,打开web服务器,注册URL处理函数。

用户管理部分在um.c中实现,

Web服务器的初始化是在default.c和webs.c中实现

url处理函数在handler.c中实现

 */

   if(initWebs()<0){

      return-1;

   }

/*

初始化Ssl认证部分

注:

在这个文档中对ssl认证不做研究

*/

#ifdefWEBS_SSL_SUPPORT

   websSSLOpen();

#endif

 

/*

 * Basiceventloop.SocketReadyreturnstruewhenasocketisreadyfor

 * service.SocketSelectwillblockuntilaneventoccurs.SocketProcess

 * willactuallydotheservicing.

 */

/*

主循环

*/

   while(!

finished){

/*

1,socketReady()函数检查是否有准备好的sock事件

2,socketSelect()函数首先把各个sock感兴趣的事件(sp->handlerMask)注册给三个集合(读,写,例外),然后调用select系统调用,然后更新各个sock的sp->currentEvents,表示各个sock的当前状态。

这两个函数在sockGen.c中实现,他们主要操作的数据是socket_t变量socketList中的handlerMask和currentEvents,socketList在sock.c中定义并主要由该文件中的socketAlloc,socketFree和socketPtr三个函数维护。

*/

if(socketReady(-1)||socketSelect(-1,1000)){

/*

该函数处理具体的sock事件

1,调用socketReady(sid)对socketList[sid]进行检查,看是否有sock事件

2,如果有sock事件,则调用socketDoEvent()函数,对事件进行处理

*/

           socketProcess(-1);

       }

       /*

该函数在cgi.c中实现,检查cgiRec变量cgilist,首先把cgi的结果输出,如果有的话,然后看cgi进程是否已对号束,如果结束,就清理该cgi进程。

Cgilist在函数websCgiHandler和websCgiCleanup中维护。

*/

       websCgiCleanup();

/*

该函数在websuemf.c中实现,功能是检查sched_t变量sched,断开超时的连接,sched变量在emfSchedCallback和emfUnschedCallback中维护

*/

       emfSchedProcess();

   }

/*

退出时的清理工作,永远不会执行到这里

*/

#ifdefWEBS_SSL_SUPPORT

   websSSLClose();

#endif

 

#ifdefUSER_MANAGEMENT_SUPPORT

   umClose();

#endif

 

/*

 * Closethesocketmodule,reportmemoryleaksandclosethememoryallocator

 */

   websCloseServer();

   socketClose();

#ifdefB_STATS

   memLeaks();

#endif

   bclose();

   return0;

}

 

3.一些想法

1, 找出他们共同的数据结构

2, 找出对这些数据结构维护(操作)的函数

3, 从http的get或者是post流程来看程序

4, 整体架构如何掌握

5, 分模块,从全局的角度看各个模块的功能

6, 从main函数起,按树型结构一层层分析下去

 

 

选择第五种方法:

1, sock模块,专门处理网络链接这一块,有这么几个文件:

sock.c和sockGen.c,sock.c是(维护)处理链接的socket_t数据结构,sockGen.c是(维护)处理链接的。

2, 对http协议数据进行操作(读取和分析),webc.c文件

3, 对具体数据的操作(asp,form…),handler.c文件

 

选择第三种方法来看程序:

假设有个http请求:

从这个http请求到服务器的处理,然后返回这样一个过程来看goahead是怎么操作的?

1,写一个http请求的url和一个head

1, 写一个http请求的post的head

 

注:

因为这次要看通整个goahead代码,所以一下子不知道以什么思路来看。

上面是一些想法,不知道从哪里开始分析一个项目的代码,也不知道取舍哪些进行程序结构和功能方面的分析。

后来的结果是写出了下面的文字。

 

 

4.goaheadmainloop源码分析

 

4.1socketReady(-1)函数分析

socketReady函数检查已建立连接的socket中是否有以下事件,如果检查到一个,就返回1,如果没有检查到,就返回零。

(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&&socketInputBuffered(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个条件中没有一个满足,则返回0。

 

4.2socketSelect(-1,1000)函数分析

socketSelect函数是系统调用select的外包函数,该函数的主要功能就是监听(?

)注册的socket事件集合,然后修改sp->currentEvents变量。

流程如下:

 

在主函数中,对socketSelect的调用是这样的:

if(socketReady(-1)||socketSelect(-1,1000)),这样做并没有对socketSelect的返回值进行检查,也就是说当socketSelect返回-1时,该条件也会满足,从而程序也会往下走,所以,这个地方也是可以优化的。

 

4.3socketProcess(-1)函数分析

socketProcess处理到达的socket事件,如果传入的参数是小于0,则会处理所有的socket的事件,如果大于0,则会处理指定的socket的事件。

下面是主要过程:

if(socketReady(sid)){

                    socketDoEvent(sp);

             }

socketReady()函数请看上面的解释,但不明白这里为什么还要用到这个函数,应该也是个可以优化的地方,我现在想到一个过程,应该是这样的:

If(socketSelect()){

/*

If(socketReady())

  socketDoEvent();

*/

socketProcess();

}

后注:

走完websGetInput()函数的分析后,因为这时仔细看到了更多的代码,上面的这个优化是不行的,因为socketReady(intsid)函数中,是sp->currentEvents,sp->handlerMask这几个标志位来判断是否有数据读写。

socketDoEvent()是对已连接的socket通过改变sp->currentEvents和sp->handlerMask来分阶段的去处理数据,

并不是一路执行到底直到把这个连接关闭的。

socketSelect()是主要还是用在有新连接到来的时候,有新连接到来才会使这个函数返回真。

socketDoEvent大致分两个阶段去处理一个连接,1是READ阶段,READ处理成功,便会设置状态到WRITE阶段,却不执行WRITE动作,2是WRITE阶段,WRITE执行完后才会结束这个连接。

当第一次主循环时,socketDoEvent()执行的是READ,所以,如果按上一个代码段,第二次执行循环时,如socketSelect()中没有新连接或数据到来,就不会往下执行了,而已有数据的连接将得不到立即的处理。

socketReady(sid)可以检查已有连接是否有数据准备好读写,所以在这里优化是错误的。

下面看看socketDoEvent函数的实现:

(1)socketDoEvent函数首先对socket的当前事件进行检查,如果是读事件并且是服务器监听socket上的读事件,说明有新连接到来,于是调用socketAccept()欢迎新连接,并使currentEvents为0,然后马上返回。

(2)如果当前不是读事件但是该socket原感兴趣的是读事件并且socket缓存中确有数据可读,那就置currentEvents为可读,这一步在socketReady函数中有做过,所以这里应该是可以去掉的。

(3)如果当前是写事件,那就看看该socket的写缓存中有没有数据,如果有并且有SOCKET_FLUSHING标志就全部输出该写缓存,这是为新的写事件做清理工作。

(4)调用事件处理函数sp->handler,该函数指针分别在两个地方进行初始化:

    1,在websDefaultHandler()函数中注册写事件,该函数在什么时候被调?

    2,在websAccept()函数中注册读事件

    两处都指向websSocketEvent()函数。

等下解释这个函数。

(5)把currentEvents置为0。

 

4.4socketAccept()函数分析

socketAccept()函数接收一个新的连接,并且调用用户注册的接收函数,这一个过程后,就把对socket_t结构的处理转换到了webs_t结构。

Sp->accept函数指针在socketOpenConnection()函数中调用socketAlloc()函数注册给监听socket的socket_t数据结构,当socketAccept()函数处理新连接时,就会把自已的Sp->accept指针及其他几个属性通过调用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这个数据结构来完成。

4.5websSocketEvent()函数分析

websSocketEvent()函数处理socket的读和写事件:

 

(1)websSocketEvent()函数根据mask决定调用读还是写函数,wp->writeSocket函数指针在websDefaultHandler()中通过调用websSetRequestSocketHandler()进行注册,指向websDefaultWriteEvent()函数。

(2)websReadEvent()函数:

websReadEvent()函数处理读事件,我们怀疑这个函数有问题,会导致web服务器宕机,因此要重点分析。

我们来看看该函数中用到的wp结构的四个状态:

先给出一个http的post头,看起来形象点:

POST/goform/formTestHTTP/1.1

Accept:

image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/*

Referer:

http:

//192.168.90.50/forms.asp

Accept-Language:

zh-cn

Content-Type:

application/x-www-form-urlencoded

Accept-Encoding:

gzip,deflate

User-Agent:

Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1;.NETCLR2.0.50727;CIBA)

Host:

192.168.90.50

Content-Length:

32

Connection:

Keep-Alive

Cache-Control:

no-cache

 

name

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

当前位置:首页 > 解决方案 > 学习计划

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

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