goahead webserver源码分析.docx

上传人:以前 文档编号:21963574 上传时间:2024-06-29 格式:DOCX 页数:22 大小:192.81KB
返回 下载 相关 举报
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(22页珍藏版)》请在三一文库上搜索。

1、W*goaheadwebserver1.一个文本架构图main()II-WebsOpenServert)II-WebsOpen1.isienOI-sockclOpenConnaccep=WebSACCe等)I卜把MKkeU结构加入数组Sockel1.islIII-WebsUrIHimdlerDefineOII-初始化WebsUriHandIerType结构的WebsUrlHandicr数组II一将UriPrcfix和回调函数绑定在WebsUrIHandIcrtWcbsUrIHandIcrMaxI1PII-WebsUrIHandIerDefine(WebsDefauhHandIer)II-初始化

2、WebsUriHandIerType结构的WebsUriHandIer85(1II一将UriPrcfix和回词函数排定在WcbsUrlHandIcrtWcbsUrIHandIcrMaxI1P-WcbsFormDefine!)卜初始化symboltable结构Sym,把名字和Wl调函数名放进“m_结构卜把SymJ结构放进hash衣中卜-WebSASPDefine()I卜-初始化symbolIablC结构$ym_t,把名字和Wl调济数名放进symj结构I卜把sym_(结构放进hash表中II(mainloop)卜一SockeiReady(三)IlsocketSelect(-l.1000)卜-轮询s

3、ocke1.isl卜-轮泡Sockel1.isi中的HandlerMaskI-中的几个变IftI-变更SockctUM中的CurrcntEvcnts“soCke(ProCeSS()II-轮询SOcket1.istI)I-SockctReadyOI-SockctDoEvcntOI-假如在新的连接(来自IiStenfd)就调用SoCke(ACCeP0卜-调用sockcacccp()liiI网函数卜-快如不是新的连接就查找Socket1.ist数组调用SoCkeUsp-handler()回调函数wcbsAccept()卜-做一些检查-sockctCrcatcHand!cr(sid.SoCKET.RE

4、ADAB1.E.WebsSockctEvcnt,lint)wp)I卜把sid注册为读事务,初始化sockcis-handlcrWCbSSoCkclEVCnt等,更新对应的sockctl.istJSkMhandIcfMssk伯等)WebsSocketEvenK)I-推断读写操作I一读WcbsRcadEvcntOII-WebsUrIHandlerRequesM)I卜查找WbsUrIHandIer数级调用和UrIPrefix对应的回调函IS(WebSFonnHdndlCro.wII-注册默认的写事务函数wp-i(eSocket=WebsDefauhWriteEventI-sockclCrcatcHa

5、ndlcr(p-sid.SOCKETeWRITAB1.E.WcbsSockctEvcn1.(int)wp)II把$id注册为写事务、初始化socketsp-handlcr=wcbsSockcEvcnt等,更新对应的Sockei1.isiSJtii1.WcbsDcfauItWntcEvcntO用户管理部分在um.c中实现,Web服务器的初始化是在dcfaultx和WCbS.c中实现url处理函数在handlcr.c中实现*/if(initWebs()p.SockelReadyreturns(ruewhenasocketisreadyfoservice.SOCkelSdCCtwillblockun

6、tilaneventoccurs.SockctProcesswillactuallydo(heservicing.W产主循环/WhiIe(Sfinished)1sockctRedy()函数检查是行有打算好的SOCk事务2.SOCkCISdeC1()函数百先把各个MKk您爱好的事务(sphandlerMask)注册给三个策合读,写,例外),然后调用SdeCl系统调用,然后更制各个sock的sp-cucn(Evcnts.表示各个SOCk的当前状态.这两个函数在SoCkGCn.c中实现,他们主要操作的数据是SoCkeU变量Sockct1.ist中的handlcrMask和CurrcntEvcnts,

7、Socket1.ist在SoCk.c中定义并主要由谡文件中的SoCkeIAUOC,SockeiFree和SocketPtt三个函数维护,/if(sockctRcady(-l)IsockctSclcc(-l.I(MX)/*该函数处理详细的$Kk瑛分1.调用SoCketReady(Sid)对SoCkel1.iSuSid)进行检杳.存是否有sock事务2,假如有SOCk事务.则调用MKketDOEYEo函数.对事芬进行处理 /socke(Process(I);I该函数在cgic中实现.检查CgiRCC变以CgiIiN首先把Cgi的结果输出,假如有的话,然后若Cgi进程是否已对号束,假如结束,就消理该

8、Cgi进程.Cgilist在函数WebsCgiHandIer和Web$CgiQeanuP中处护心 /WcbsCgiCIeanupO:/*该函数在web$uemf.c中实现,功能是检变Sd)ed_t变;ASehed,断开制时的连接,SChe1变t在emfScheack中雄:护 /CmfSChcdProCe$虱):退出时的清理工作,恒久不执行到这里ttifdefVEBS_SS1._SUPPORTWCbSSS1.CIOSCO:#endifWifdefUSER_MANAGEMENT_SUPPORTumClosc():#CndifClosethesocketmodule,reportmemoryleak

9、sandclosethememoryalkxrator/WebSCloSeSerVea);sockelClosc();#ifdcfBfrATSnm1.eaks();#endifbcloseO:returnO:I3.一联想法1. 找出他们共同的数据结构2. 找出对这些数据结构维护(操作)的函数3. 从的get或者是PON流程来看程序4. 整体架构如何驾取5. 分模块,从全局的角度有各个模块的功能在主函数3xtSockdSeIccJ的调用是这样的:if(sockeReady(-l)IlSockeiSekcU-1.100O),这样做并没方一对$oCketSdeu的返回值进行检作也就是说节SoCke(

10、SekCl返回-1时,该条件也会满意,从而程序也会往下走,所以,这个地方也是可以优化的.4.3SoCkeIPrDCeSM-D函数分析SOCkeP11XXSS处理到达的SOCkel事务,例如传入的参数是小于0.则会处理全部的SoCkCt的事务,假如大于。.则会处理指定的StKka的事务.下面是主要过程:if(SockeiReady(Sid)(sockelDEvenl(sp);)SoCkClRCadyo函数请看上面的说明,但不明臼这里为什么还要用到这个函数,应当也是个可以优化的地方,我现在想到一个过程.应当是这样的:IftsockeiSeIect()|/*If(SockclReadyO)Socke

11、tDoEvcntO;/SOCkaPnXXsS():后注:走完WcbSGCHnPUU)函数的分析后,因为这时细致看到了史多的代码,上面的这个优化是不行的,因为M)CkCIRCady(iniSid)函数中,是S1CUnenIEVeHts,sp-hancun,en(Events和sp-handlerMask来分阶段的去处在数据.并不是路执行究竟直到把这个连接关闭的.SockctScIect。是主要还是用在有新连接到来的时候,有新连接到来才会使这个函数返回真。SoCkCtDOEVCm大致分两个阶段去处理一个连接,I是READ阶段.READ处理胜利,便会设跣状态到WRITE阶段,却不执行WRITE动作,

12、2是WRrrE阶段,WRITE执行完后才会结束这个连接,当第一次主循环时,$oCketDOEvent。执行的是READ,所以,假如按上个代码段,其次次执行循环符,如sckeiSdi()中没有新连接或数据到来,就不会往卜执行了,而己有数据的连接将得不到马上的处理,SoCkaREdy(Sid)Ur以检查己有连接是否有数据打算好读写.所以在这里优化是惜误的.下面看看$oCkCtDoEYCnl函数的实现:(I)MKkelDoEvenl函数首先对socket的当前事务进行桧查,假如是读事务并且是服务器监听socket上的读事务,说明有新连接到来,于是调用SOCkCtACCCPU)欢迎新连接.并使CUrr

13、Cn心CmS为0.然后立刻返回.(2)假如当前不是读事务但是诬SoCka原感爱好的是读事务并且socket谡存中确有数据可读,那就置CurrenlEvents为可读,这-步在SwketReady函数中有做过,所以这里应当是可以去掉的.(3)假如当前是写事芬,那就看看该$oCkCt的写缓存中书没书数据,假如有井且有SoCKET_F1.USHlNG标记就全部输出该写缓存,这是为新的写少务做清理工作,(4)调用事务处理函数SPAhandIer,该函数指计分别在两个地方进行初始化:1.在WebSDCfaUhHandIE涵数中注册写事务,谈话数在什么时候被调?2,在Web$ACCCP0函数中注册波事务两

14、处都指向WebSSoCke(EVent()函数:等下说明这个函数、(5)把CUlTenlEVenIS置为0。4.4 SoCketACCCPto函数分析scke(Accepacccpt函数指针在SoCkCle)PenCOnneeI沁n()函数中调用sdgAllocO函数注册给监听sockel的socket数据结构.当sckctAcc叩V)函数处珅新连接时,就会把自己的Sp-acccpt指计及其他几个品性通过调用SockctAIloc(sp-hos(,sp-po11,spacccpl.spfhgs函数乂给f新的连接,留意:谓用完这个后,会更新新的nsp-flg&=SOCKETJJSTENING,把

15、该连接和监听连接区分开。然后.监所SoCkct用自己的Spacccpt.、型岫处本地通足东地E机动何用枝H71:、WlHS1(AlRH?lISTwckeCre11tdI*ndkrtid,7乂3d的谕”二ASOCKKT.RAI)AB1.E.,web*Sockcthvcft.(E)wp)/CZEj经过WebSAC“pH)函数后,将走出SoCkCt层,来到WCbS,结构层.以后对读和写的操作都通过操作WebS这个数据结构来完成C4.5 WebSSoCkCtEVClIt()函数分析WCbSSOekCIEVCm()函数处理socket的读和写事务:WCbSS以RCqU对SoCkCIHAndIero进行注

16、册,指向WebSDdhUkWriteEVeNo函数.函数指针在WebsDcfauItHandIerO中通过询用(2)WebSReadEVemo函数:WCARgdEsl()函数处理读事务.我们怀疑这个函数有问题,公导致WCb服务据容机,因此要重点分析Q我们来看行读函数中用到的WP结构的四个状态:先给出一个的POSt头.存起来形望点:POSTgoformfo11nTesl/1.1Accept:imagc/gif.imagc/x-xbitmap.imagc/jpeg.image/Pjpeg,application.x-shrkwave-Hash,applicatio11vnd.ms-cxcel.ap

17、plicationvnd.ms-powex)int.aplicationmswod,Accepl-1.anguage:zhnContent-Type:applcatiotx-w-w-fbrm-ur!cnc11agsI=VEBS_POST_REQUEST:wqucry=bstrdup(B_1.,query);wp-hos(=bs(nJup(B_1.host);wp-pa(h=bsirdup(B-1.path);wp-protocol=bstrdup(B_1.proto);w-protoVersion=bsiixiuplB,,protoVer);对wpnags几个敢要的赋俏:WEBS_CG1.RE

18、QUEST,WEBS.ASP.WEBS_1.oCAjPAGE等,分析好第一行后,调用HngqFIushO函数把wpheaderItt相当于清零的操作,把各个指针都指向这个媛冲的起先处,假如WebSParSeFiN()函数调用胜利,就转到WEBSIEADER状态:WP-ale=W1.BSHEADER.按程序的游程.这个时候仍在循环中,立刻就会转到WEBS_HEADER状态机,但是会这样叫?(2)WEBSIEADER,白先(1)以后(经过WEBS_BEGIN),除非WebSGeUnPUloo函数调用不胜利,否则就会执行到WEBSJEADER状态机,这个时候我们就要看看webSGCUnPUu)函数九

19、因为这个函数假如调用不胜利.是不会执行到WEBS_HEADER的.WcbsGctInputO函数分析:函数功能:接收客户端的数据:函数返回值;-1,表示出错或者恳求已经被处理0.表示告知词川者还有更多的数据待读取1.我示数据已羟读好.WebsGeIInpUt()函数的处理过程:留意上图中的两个注解,1是读取SoCkel时,一次G多读256个字节,2是POSI的数据长度在WCbSPanRequZ(wp)函数中得到,也就是说假如个连接首次词川WdWGCUnPUto函数,应当执行的是=W)的那条分支.下面试着走一个流程,当WebeCunPUto函数接收上例PE头时.会怎么处理.首先,程序公进入=0分

20、支,接着会进入SOCkeIGeIS。函数,我们在这个函数里去走一圈:SOCkCIGCbio函数从SoCkCt中读取一行,然后返回.如现在读到的是:POSTZgofornVformTest/I.I明显程序将干触走到输出:这里,井返山,WcbecUnputO函数的上层调用函数WCbSRSdEVenU)起先进入状态机WEBS_BEGlN进行处理,分析POSt头的第行,分析胜利将状态转到WEBS.HEADER,这时其次次调用WebSGeUnPUm这里WP结构除了SIMe变增变了.其他都没变,所以Ien还是0,还是调用SOCkelGeE)函数从SoCkeI中读取一行,我们这都畏!设读胜利,先不想不胜利的

21、事.现在我们到WEBS_HEADER状态机.把读到的数据放入wp-hcadcr援存变fit中.这样始终读到Authorization:BasicYWRtaW46YWRtaW4这时,wpheader缓存中存放了除第,,行以外的head,好,到这时,WebSReadEVent()还会再调用,诙WebGelnput(),我们看这MI会有什么状况。另外先说卜WEBSjEADER状态机中为什么公有ringqPutStrtwp-headcr.T(-):1-iij,是因为在MKkelGC(So函数以“”为一行结束标记来返回这一行.但是并没有包括所以在这里总是会加上一个以便后面的程序做分析.接着读,还是走到S

22、OCkCtGcO)*buf=ballocAscToUni(char*)lq-serv.Ien);Ielse(buf=NU1.1.:ringqFlush(lq;returnlcn:这里用得很奇妙因为是不加入缓存,所以ICn=(lq附为0,这时天线地义返【可0了,也就是读完head了,我们在当WebSGCUnPUIo收到SOCkelGe(SO的0返11值时,会E么样处理,按上图,程序就会走到wp-stalc这个条件分支,当前状愈是WEBS_HEADER,所以会执行WebSParSCRCqUcSt()函数,这个函数公尽情的分解这个头文件.而立刻要起到作用的是在分解时处理的-个变!:wp-fiagsI

23、=VEBS_C1.EN,这是依据头中的Content-1.ength:116得到的。假如头中没有这行会怎么办?那么首先wpfla默中不会有WEBS_C1.EN这一位,并且WPden也不会被初始化。下一步进入WP痴眇条件,就是上图中的入口程序如下,if(wp-agsWEBS_POST_REQUEST)if(wflags&WEBS,C1.EN)(wp-sta(e=WEBS_POST_C1.EN:clen=wp-clcn:)dscwp-state=WEBS_POST;clen=1;)if(clcnO)return0;Ireturn1;假如是WEBS_PoST.REQUEST.则接着到条件wp-tla

24、gs,假如是WEBS_C1.EN(假如是标准头,确定是有这个的,就把wp-statc=WEBS_PoST_C1.EN,然后的CIen=WPlen,留想,这里CIen可能是O,Conteni-1.engih:O假如wplHgs中没有WEBS_C1.EN这一位,则设置ws(ule=WEBS_POST;和clcn=1,接着依据CIen的假大于。返但10,上面说了有可能等于零的状况.那么会返回I(表示没行数据可读了八我state=WEBS_PoST_C1.ENMIen=(WP-KlenWEBS_SoCKET_BUFSIZ)?WEBS_SOCKET_BUFSIZ:wp-xlen;dscIcn=0;.那么

25、这里条件Ien将会X),于是我们走进上图中的IenX)分支,调用SoCkeIReadO函数,这里不探讨出错状况,SwkelRead()函数将读完城大长度不超过WEBS_SoCKET-BUFSlZ的PoSl数据,然后WCbSGeUnpU1()返回1,我们又回到WebSReadEVen1()函数.在WCbSReadEcr11O函数我们进入WEBS_PoST_C1.EN状态机.在这个处理模块制读完用个post数据,然后送WCbSUrlHandlaRCqUCWWP画数进行处理。这时WebSREdEVCnH)函数算是动用圆满/.乳done为1退出函数.上面就是读客户端p。Sl数据并且该数据标有长度状况卜

26、的整个流程.在没有长度的状况下,假如有阅读器访问,除其间读器有bug.正常是不会出现这种状况的.没长度时Ien=0,WCbeCUnPu1()进入SOCkCIGclSo那分支,然后始终读,读到出错nby(esO)或者是读完nbytes=O)为止,我们先看sialc,假如是WEBS_POST状态机,则调用WCbSUrIIkIndiCrReMUE(WP)函数进行处理,也就是在这里走完fPON没行ICn状况下的流程.而我们再有回头在WebSRCadE、EO函数中WEBS_PoST状态机的功能只是把数据谈到Wh&r中.假如不是在WEBS-POST状态机,程序将冏用wcbsDonc(wp.0)函数干脆把该

27、连接关见为什么呢?假如程序能走到这里,又不是WEBS_PC)ST.那更不行能是WEBS_PoST_1.EN状态,那只有可能是WEBS_BEGlN或VEBS_HEADER状态,WEBS.BEGIN只读第一行POSTgoformWircIessAdvanced/1.1而读这一行是不会出现EOF状态的.1是假如下面还有数据,出现EOF就说明这个head有问题.2是例如下面没有数据,应当是以“”结尾的,如所分析.MckciGcstate=WEBS_POST)(WebsUrIHandIerRequest(Wp);dscwcbsDonc(wp,0);I现在Web$GeUnPU1()函数还有一个分支没有分析

28、,就是在的状况卜,没有进入上图的接口,这种状况卜发生什么?苴先请看下面的头:GET),forns.asp/1.1Accept:imagc/gif,iagcx-xbitmap.imagc/jpcg.image/PjPcgapplication-shockwavc-llash,application/Vnd.nccl,applicalion/vnd.ms-powcrpoint,applica(ionmsworl.*f*AccepJ-1.anguage:zh-cnAcccpags&WEBS_POST_REQUEST这个条件不成立,所以我给出上面的一个GET头,这时wp-ags中应当在WEBS-BEG

29、1N状态机下的WebSParSCFiEO函数中没有被设置为WEBS_POST_REQUEST,这里不得不插入15WCbSPaniCFiEo函数中的代码说明状况?if(gstrcmp(op,T(mGETm)!=0)if(gstmXop,T(POST,)二二0)(wp-ags=VEBS_POST_REQUEST:)elseif(gs(rcmp(op.T(HEAD)=0)wp-tlagsI=VEBS_HEAD_REQUEST;)elseIwebsError(wp.40().T(wBadrequest(ypc*):return-1;I审来,对于GET头,WhXl侬并不须要设置一个WEBS_GET_XX

30、X什么的标记位缘由说清了,按上图,程序进入WebsUriHandIerRequest(Wp)Ffi.WCbSUdHilndkrRCqUeSuWP)函数会怎么处理上面给出的这个GET头,WCbJiurlHandICrRCquCJit(WP)依据UrIPrCnX来调用注册好的旧词函数.先说UrlPrCHX.他是指gofo11nxxx/cgi_birUyyy中的gofcrm和/cgi_bin这些东西假如一个I:R1.是这样的“fo11ns.a卬那么他的UrIPrCfiX为二在主Imin。函数中,注册了对这个UrIPrdlX的WI网函数为:wcbsUrlHarilcrDcfinc(TC,)tNU1.1

31、.0.WebsDefauItHandIer.WEBSjAND1.ER_1.AST);即WCbSDChHJltHandICrO函数.WCbSUrlHandICrRCqUCSt(WP)函数通过筐找WebSUrIHandlcr数组会得到UrIPrcfix和E调函数的对应关系,然后调用回调函数,现在我们进到WcbsDcfauItHandIcrO,在SOCkclpmCCSUI)函数分析的第(4)点中有个疑问到这里就不再是疑问了WebsDcfaukHandIcrOftttffJ最终调RhwebsSelRequestSkelHandlertw.SOCKETWRITAB1.E.WCbSDefUUIIWriic

32、Evcnl):注册该wp连接写事务的回调函数,并把WP的感量好的事务handlerMask改为SOCKET.WRITAB1.E,这样当其次次执行主循环时,想想回到WCbSSoCkctE5t()函数,就会调用到写事务的函数WCbSDCfalIItWritCEYenV).通过wp-wri(cSkct指针4.6 WebSCgielealWpO函数分析该函数清除执行完的CGI进程。4.7 CmfSchCdPnXeSS()函数分析CmNCbaIprOCC网)函数检查超时的连接.假如有超时的连接就会把这个连接清理掉,这里要留意程序中是怎么设置超时的起起始时间的.在WCKRCadEcnt()函数中.调用WC

33、bSSCtTimCMark(WP)为该连接设置一个时间微.超时就是相对于这个时间的,但是请想下假如该连接始终没育数据到来的话,仅完成三次握手(不了解内核会不会时这样的连接有个超时机刎,叙如有,我下面就是白说),因为不行能执行到WebSReadEVemO函数,加么超时机制将对谈连接无效,可以想象有许多这样的题意连接没有被清除将公奢侈系统资源,所以当accept这个连接的时候,就用WCbsSeEmeMiH*wp)为该连接设置一个时间戳.这个动作可以放在WCbSAlloC()函数中.这个函数被WChSACCePt()函数调用.作用是初始化一个新的Webs结构的连接.帙如在超时的书数据来,这个时间戳将在WebSRCadEVento函数更改成新的:假如没有新的数据.那超时之后,服务器利断开这个连接,这样并不会影响系统运行,因此是可行的,可以用(dnel192.168.0.5080这样连接上服务器但是不发任何字符到服务器进行测试。

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

当前位置:首页 > 研究报告 > 信息产业


经营许可证编号:宁ICP备18001539号-1