goahead webserver源码分析
(2010-01-17 10:12:16) 标签: 杂谈
1.一个txt文本架构图 main() |
|--websOpenServer() | |-- websOpenListen()
| |--socketOpenConnection() | |--打开webServer服务器
| |--初化socket_t结构(注册websAccept()回调函数(socket_t sp->accept= websAccept)等)
| |--把socket_t结构加入数组socketList | |
|--websUrlHandlerDefine()
| |--初始化websUrlHandlerType结构的websUrlHandler数组
| |--将urlPrefix和回调函数绑定在websUrlHandler[websUrlHandlerMax]中 |
|--websUrlHandlerDefine(websDefaultHandler)
| |--初始化websUrlHandlerType结构的websUrlHandler数组
| |--将urlPrefix和回调函数绑定在websUrlHandler[websUrlHandlerMax]中 | | |
|--websFormDefine()
| |--初始化symbol table结构sym_t,把名字和回调函数名放进sym_t结构 | |--把sym_t结构放进hash表中 |
|--websAspDefine()
| |--初始化symbol table结构sym_t,把名字和回调函数名放进sym_t结构 | |--把sym_t结构放进hash表中 | |
|(main loop)
----|--socketReady(-1) || socketSelect(-1, 1000)
^ |--轮询socketList |--轮询socketList中的handlerMask | | |--中的几个变量 |--改变socketList中的currentEvents | |
| |--socketProcess()
^ | |--轮询socketList[] | | |--socketReady() | | |--socketDoEvent()
| | |--如果有新的连接(来自listenfd)就调用socketAccept() | | |--调用socketAlloc()初始化socket_t结构 | | |--把socket_t结构加入 socketList数组 | | |--调用socket_t sp->accept()回调函数 | |
| | |--如果不是新的连接就查找socketList数组调用socket_t sp->handler()回调函数
| | | | --|
websAccept() |--做一些检查
|--socketCreateHandler(sid, SOCKET_READABLE, websSocketEvent, (int) wp) | |--把sid注册为读事件,初始化socket_t sp->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_t sp->handler = websSocketEvent等, 更新对应的socketList数组
websDefaultWriteEvent() |
|--写数据,不包括asp页面
2.跟着main走
Main函数很简短,所以可以对他的代码进行一行一行注释,如下: int main(int argc, char** argv) {
bopen(NULL, (60 * 1024), B_USE_MALLOC);
signal(SIGPIPE, SIG_IGN);
if (initWebs() < 0) { return -1; }
#ifdef WEBS_SSL_SUPPORT websSSLOpen(); #endif
while (!finished) {
if (socketReady(-1) || socketSelect(-1, 1000)) {
socketProcess(-1); }
websCgiCleanup();
emfSchedProcess(); }
#ifdef WEBS_SSL_SUPPORT websSSLClose(); #endif
#ifdef USER_MANAGEMENT_SUPPORT umClose(); #endif
websCloseServer(); socketClose(); #ifdef B_STATS memLeaks(); #endif bclose(); return 0; }
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.goahead mainloop源码分析
4.1 socketReady(-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的缓存中有可读的数据,