版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
goaheadwebserver 源碼分析1.一個txt文本架構(gòu)圖main()卜-websOpenServer()|--websOpenListen()卜-socketOpenConnection()卜-打開webServer服務器|--初化socket_t結(jié)構(gòu)(注冊websAccept()回調(diào)函數(shù)(socket_tsp->accept=websAccept)等)|--把socket_t結(jié)構(gòu)加入數(shù)組socketList卜-websUrlHandlerDefine()| |--初始化websUrlHandlerType結(jié)構(gòu)的websUrlHandler數(shù)組| |--將urlPrefix和回調(diào)函數(shù)綁定在websUrlHandler[websUrlHandlerMax]中|卜-websUrlHandlerDefine(websDefaultHandler)| |--初始化websUrlHandlerType結(jié)構(gòu)的websUrlHandler數(shù)組| |--將urlPrefix和回調(diào)函數(shù)綁定在websUrlHandler[websUrlHandlerMax]中II|卜-websFormDefine()| |--初始化symboltable結(jié)構(gòu)sym_t,把名字和回調(diào)函數(shù)名放進sym_t結(jié)構(gòu)| |--把sym_t結(jié)構(gòu)放進hash表中|卜-websAspDefine()| |--初始化symboltable結(jié)構(gòu)sym_t,把名字和回調(diào)函數(shù)名放進sym_t結(jié)構(gòu)| |--把sym_t結(jié)構(gòu)放進hash表中|||(mainloop)|--socketReady(-1)||socketSelect(-1,1000)A |--輪詢socketList |--輪詢socketList中的handlerMask卜-中的幾個變量|--卜-中的幾個變量|--改變socketList中的currentEvents|卜-socketProcess()A| |--輪詢socketList[]|| |--socketReady()|| 卜-socketDoEvent()I| 卜-如果有新的連接(來自listenfd)就調(diào)用socketAccept()|| |--調(diào)用socketAlloc()初始化socket_t結(jié)構(gòu)|| |--把socket_t結(jié)構(gòu)加入socketList數(shù)組|| |--調(diào)用socket_tsp->accept()回調(diào)函數(shù)II|| |--如果不是新的連接就查找socketList數(shù)組調(diào)用socket_tsp->handler()回調(diào)函數(shù)IIwebsAccept()卜-做一些檢查卜-socketCreateHandler(sid,SOCKET_READABLE,websSocketEvent,(int)wp)| |--把sid注冊為讀事件,初始化socket_tsp->handler=websSocketEvent等,更新對應的socketList數(shù)組(handlerMask值等)websSocketEvent()|--判斷讀寫操作卜-讀websReadEvent()| 卜-websUrlHandlerRequest()| |--查找wbsUrlHandler數(shù)組,調(diào)用和urlPrefix對應的回調(diào)函數(shù)(websFormHandler(),websDefaultHandler()等)||--寫,調(diào)用(wp->writeSocket)回調(diào)函數(shù)websFormHandler()|--跟據(jù)formName查找hash表,調(diào)用用戶定義的函數(shù)websDefaultHandler()I--處理默認的URL請求,包括asp頁面卜-websSetRequestSocketHandler()I I--注冊默認的寫事件函數(shù)wp->writeSocket=websDefaultWriteEventI|--socketCreateHandler(wp->sid,SOCKET_WRITABLE,websSocketEvent,(int)wp)I I--把sid注冊為寫事件,初始化socket_tsp->handler=websSocketEvent等,更新對應的socketList數(shù)組websDefaultWriteEvent()II--寫數(shù)據(jù),不包括asp頁面2跟著main走Main函數(shù)很簡短,所以可以對他的代碼進行一行一行注釋,如下:intmain(intargc,char**argv){/*Initializethememoryallocator.Allowuseofmallocandstartwitha60Kheap.Foreachpagerequestapprox8KBisallocated.60KBallowsforseveralconcurrentpagerequests.Ifmorespaceisrequired,mallocwillbeusedfortheoverflow.*//*首先分配一個大的內(nèi)存塊(60*1024字節(jié)),以后只要是以b開頭的對內(nèi)存操作的函數(shù)都是在這個已經(jīng)分好的內(nèi)存塊上的操作,這些操作在Balloc.c中實現(xiàn)。*/bopen(NULL,(60*1024),B_USE_MALLOC);/*忽略SIGPIPE信號*/signal(SIGPIPE,SIG_IGN);/*Initializethewebserver初始化用戶管理部分,打開web服務器,注冊URL處理函數(shù)。用戶管理部分在um.c中實現(xiàn),Web服務器的初始化是在default.c和webs.c中實現(xiàn)url處理函數(shù)在handler.c中實現(xiàn)*/if(initWebs()<0){return-1;}/*初始化Ssl認證部分注:在這個文檔中對ssl認證不做研究*/#ifdefWEBS_SSL_SUPPORTwebsSSLOpen();#endif/*Basiceventloop.SocketReadyreturnstruewhenasocketisreadyforservice.SocketSelectwillblockuntilaneventoccurs.SocketProcesswillactuallydotheservicing.*//*主循環(huán)*/while(!finished){/*socketReady()函數(shù)檢查是否有準備好的sock事件socketSelect()函數(shù)首先把各個sock感興趣的事件(sp->handlerMask)注冊給三個集合(讀,寫,例外),然后調(diào)用select系統(tǒng)調(diào)用,然后更新各個sock的sp->currentEvents,表示各個sock的當前狀態(tài)。這兩個函數(shù)在sockGen.c中實現(xiàn),他們主要操作的數(shù)據(jù)是socket」變量socketList中的handlerMask和currentEvents,socketList在sock.c中定義并主要由該文件中的socketAlloc,socketFree和socketPtr三個函數(shù)維護。*/if(socketReady(-1)||socketSelect(-1,1000)){/*該函數(shù)處理具體的sock事件1,調(diào)用socketReady(sid)對socketList[sid]進行檢查,看是否有sock事件2,如果有sock事件,則調(diào)用socketDoEvent()函數(shù),對事件進行處理*/socketProcess(-1);}/*該函數(shù)在cgi.c中實現(xiàn),檢查cgiRec變量cgilist,首先把cgi的結(jié)果輸出,如果有的話,然后看cgi進程是否已對號束,如果結(jié)束,就清理該cgi進程。Cgilist在函數(shù)websCgiHandler和websCgiCleanup中維護。*/websCgiCleanup();/*該函數(shù)在websuemf.c中實現(xiàn),功能是檢查sched_t變量sched,斷開超時的連接,sched變量在emfSchedCallback和emfUnschedCallback中維護*/emfSchedProcess();}/*退出時的清理工作,永遠不會執(zhí)行到這里*/#ifdefWEBS_SSL_SUPPORTwebsSSLClose();#endif#ifdefUSER_MANAGEMENT_SUPPORTumClose();#endif/*Closethesocketmodule,reportmemoryleaksandclosethememoryallocator*/websCloseServer();socketClose();#ifdefB_STATSmemLeaks();#endifbclose();return0;}3.—些想法找出他們共同的數(shù)據(jù)結(jié)構(gòu)找出對這些數(shù)據(jù)結(jié)構(gòu)維護(操作)的函數(shù)從http的get或者是post流程來看程序4, 整體架構(gòu)如何掌握5, 分模塊,從全局的角度看各個模塊的功能6,從main函數(shù)起,按樹型結(jié)構(gòu)一層層分析下去選擇第五種方法:1, sock模塊,專門處理網(wǎng)絡鏈接這一塊,有這么幾個文件:sock.c和sockGen.c,sock.c是(維護)處理鏈接的socket_t數(shù)據(jù)結(jié)構(gòu),sockGen.c是(維護)處理鏈接的。2, 對http協(xié)議數(shù)據(jù)進行操作(讀取和分析),webc.c文件3,對具體數(shù)據(jù)的操作(aspform…),handler.c文件選擇第三種方法來看程序:假設有個http請求:從這個http請求到服務器的處理,然后返回這樣一個過程來看goahead是怎么操作的?1,寫一個http請求的url和一個head1,寫一個http請求的post的head注:因為這次要看通整個goahead代碼,所以一下子不知道以什么思路來看。上面是一些想法,不知道從哪里開始分析一個項目的代碼,也不知道取舍哪些進行程序結(jié)構(gòu)和功能方面的分析。后來的結(jié)果是寫出了下面的文字。4.goaheadmainloop源碼分析socketReady(-l)函數(shù)分析socketReady函數(shù)檢查已建立連接的socket中是否有以下事件,如果檢查到一個,就返回1,如果沒有檢查到,就返回零。sp->flags&SOCKET_CONNRESET,如果該socket的flag標志為SOCKET_CONNRESET(該標志在哪里設置(初始化)的?),則調(diào)用函數(shù)socketCloseConnection(該函數(shù)后面會解釋)關閉該socket連接,然后返回0;sp->currentEvents&sp->handlerMask,如果該socket當前的事件和他要處理的事件相同,就返回1,告訴調(diào)用socketReady的函數(shù)有socket準備好被處理了;sp->handlerMask&SOCKET_READABLE&&socketInputBuffered(sid)>0,如果該socket要處理的事件是SOCKET_READABLE并且該socket的緩存中有可讀的數(shù)據(jù),則調(diào)用socketSelect函數(shù)(為什么在這里要調(diào)用這個函數(shù),看了下socketSelect,應該是為了設置sp->currentEvents|=SOCKET_READABLE,所以這里應可以優(yōu)化),然后返回1,告訴調(diào)用socketReady的函數(shù)有socket準備好被處理了;socketReady函數(shù)根據(jù)傳入的參數(shù)sid決定是檢查id為sid的socket(當sid大于0),還是遍歷整個socketList(當sid小于0),如果以上3個條件中沒有一個滿足,則返回0。socketSelect(-1,1000)函數(shù)分析socketSelect函數(shù)是系統(tǒng)調(diào)用select的外包函數(shù),該函數(shù)的主要功能就是監(jiān)聽(?)注冊的socket事件集合,然后修改sp->currentEvents變量。流程如下:
在主函數(shù)中,對socketSelect的調(diào)用是這樣的:if(socketReady(-l)||socketSelect(-1,1000))這樣做并沒有對socketSelect的返回值進行檢查,也就是說當socketSelect返回-1時,該條件也會滿足,從而程序也會往下走,所以,這個地方也是可以優(yōu)化的。socketProcess(-l)函數(shù)分析socketProcess處理到達的socket事件,如果傳入的參數(shù)是小于0,則會處理所有的socket的事件,如果大于0,則會處理指定的socket的事件。下面是主要過程:if(socketReady(sid)){socketDoEvent(sp);socketReady()函數(shù)請看上面的解釋,但不明白這里為什么還要用到這個函數(shù),應該也是個可以優(yōu)化的地方,我現(xiàn)在想到一個過程,應該是這樣的:lf(socketSelect()){/*lf(socketReady())socketDoEvent();*/socketProcess();}后注:走完websGetlnput()函數(shù)的分析后,因為這時仔細看到了更多的代碼,上面的這個優(yōu)化是不行的,因為socketReady(intsid)函數(shù)中,是sp->currentEvents,sp->handlerMask這幾個標志位來判斷是否有數(shù)據(jù)讀寫。socketDoEvent()是對已連接的socket通過改變sp->currentEvents和sp->handlerMask來分階段的去處理數(shù)據(jù),并不是一路執(zhí)行到底直到把這個連接關閉的。socketSelect()是主要還是用在有新連接到來的時候,有新連接到來才會使這個函數(shù)返回真。socketDoEvent大致分兩個階段去處理一個連接,1是READ階段,READ處理成功,便會設置狀態(tài)到WRITE階段,卻不執(zhí)行WRITE動作,2是WRITE階段,WRITE執(zhí)行完后才會結(jié)束這個連接。當?shù)谝淮沃餮h(huán)時,socketDoEvent()執(zhí)行的是READ,所以,如果按上一個代碼段,第二次執(zhí)行循環(huán)時,如socketSelect()中沒有新連接或數(shù)據(jù)到來,就不會往下執(zhí)行了,而已有數(shù)據(jù)的連接將得不到立即的處理。socketReady(sid)可以檢查已有連接是否有數(shù)據(jù)準備好讀寫,所以在這里優(yōu)化是錯誤的。下面看看socketDoEvent函數(shù)的實現(xiàn):
(1)socketDoEvent函數(shù)首先對socket的當前事件進行檢查,如果是讀事件并且是服務器監(jiān)聽socket上的讀事件,說明有新連接到來,于是調(diào)用socketAccept()歡迎新連接,并使currentEvents為0,然后馬上返回。如果當前不是讀事件但是該socket原感興趣的是讀事件并且socket緩存中確有數(shù)據(jù)可讀,那就置currentEvents為可讀,這一步在socketReady函數(shù)中有做過,所以這里應該是可以去掉的。如果當前是寫事件,那就看看該socket的寫緩存中有沒有數(shù)據(jù),如果有并且有SOCKET_FLUSHING標志就全部輸出該寫緩存,這是為新的寫事件做清理工作。調(diào)用事件處理函數(shù)sp->handler,該函數(shù)指針分別在兩個地方進行初始化:1,在websDefaultHandler()函數(shù)中注冊寫事件,該函數(shù)在什么時候被調(diào)?
2,在websAccept()函數(shù)中注冊讀事件兩處都指向websSocketEvent()函數(shù)。等下解釋這個函數(shù)。(5)把currentEvents置為0。socketAccept()函數(shù)分析socketAccept()函數(shù)接收一個新的連接,并且調(diào)用用戶注冊的接收函數(shù),這一個過程后,就把對socketAccept()函數(shù)接收一個新的連接,并且調(diào)用用戶注冊的接收函數(shù),這一個過程后,就把對socket_t結(jié)構(gòu)的處理轉(zhuǎn)換到了webs_t結(jié)構(gòu)。Sp->accept函數(shù)指針在socketOpenConnection()函數(shù)中調(diào)用socketAlloc()函數(shù)注冊給監(jiān)聽socket的socket_t數(shù)據(jù)結(jié)構(gòu),當socketAccept()函數(shù)處理新連接時,就會把自已的Sp->accept扌旨針及其他幾個屬性通過調(diào)用socketAlloc(sp->host,sp->port,sp->accept,
sp->flags)函數(shù)又給了新的連接,注意,調(diào)用完這個后,會更新新的nsp->flags&=~SOCKET_LISTENING,把該連接和監(jiān)聽連接區(qū)別開。然后,監(jiān)聽socket用自已的Sp->accept調(diào)用到websAccept()函數(shù),但是傳遞的第一個參數(shù)是新連接的id:nid。這也應該是個技巧吧。websAccept()函數(shù)功能:池Iport'池Iport'【認疋門£訕}I.OCXIR1:QULST如製ipacid"上和也評盤杓電LHL訪詢.則儀輕口n->flagn\\I-:BSiI.C1CA1btE':QUk:S'i/snck?[C:e;i[ellibti^3ed訃d,S(X細IKLAIJAFilJ?.webs$CKki:tTArtiiE.迺也經(jīng)過websAccept()函數(shù)后,將走出socket層,來到webs_t結(jié)構(gòu)層,以后對讀和寫的操作都通過操作webs_t這個數(shù)據(jù)結(jié)構(gòu)來完成。websSocketEvent()函數(shù)分析websSocketEvent()函數(shù)處理socket的讀和寫事件:
(1)websSocketEvent()函數(shù)根據(jù)mask決定調(diào)用讀還是寫函數(shù),wp->writeSocket函數(shù)指針在websDefaultHandler()中通過調(diào)用websSetRequestSocketHandler()進行注冊,指向websDefaultWriteEvent()函數(shù)。(2)websReadEvent()函數(shù):websReadEvent()函數(shù)處理讀事件,我們懷疑這個函數(shù)有問題,會導致web服務器宕機,因此要重點分析。
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:0/forms.aspAccept-Language:zh-cnContent-Type:application/x-www-form-urlencodedAccept-Encoding:gzip,deflateUser-Agent:Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1;.NETCLR2.0.50727;CIBA)Host:0Content-Length:32Connection:Keep-AliveCache-Control:no-cachename=adfs&address=fdsafdsa&ok=OK(1)WEBS_BEGIN,該狀態(tài)是在websAccept()函數(shù)調(diào)用wbesAlloc()函數(shù)初始化wp結(jié)構(gòu)時被設置的,如果是在這個狀態(tài),該函數(shù)就調(diào)用websParseFirst()函數(shù)分析http頭的第一行數(shù)據(jù),在websParseFirst()中,主要會對wp結(jié)構(gòu)的下面幾個數(shù)據(jù)進行操作:wp->flags|=WEBS_POST_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等,分析好第一行后,調(diào)用ringqFlush()函數(shù)把wp->header做相當于清零的操作,把各個指針都指向這個緩沖的開始處。如果websParseFirst()函數(shù)調(diào)用成功,就轉(zhuǎn)到WEBS_HEADER狀態(tài):wp->state=WEBS_HEADER。按程序的流程,這個時候仍在循環(huán)中,馬上就會轉(zhuǎn)到WEBS_HEADER狀態(tài)機,但是會這樣嗎?(2)WEBS_HEADER,首先(1)以后(經(jīng)過WEBS_BEGIN),除非websGetlnput()()函數(shù)調(diào)用不成功,否則就會執(zhí)行到WEBS_HEADER狀態(tài)機,這個時候我們就要看看websGetInput()函數(shù)了,因為這個函數(shù)如果調(diào)用不成功,是不會執(zhí)行到WEBS_HEADER的。websGetInput()函數(shù)分析:函數(shù)功能:接收客戶端的數(shù)據(jù);函數(shù)返回值:-1,表示出錯或者請求已經(jīng)被處理0,表示告訴調(diào)用者還有更多的數(shù)據(jù)待讀取1,表示數(shù)據(jù)已經(jīng)讀好。websGetInput()函數(shù)的處理過程:■i-K.qrtilHli■iia.b.REgZi.^TLZ(f 玳岸I■i-K.qrtilHli■iia.b.REgZi.^TLZ(f 玳岸I;內(nèi).(i*MrE..?{Al;七盤譏訂1注意上圖中的兩個注解,1是讀取socket時,一次最多讀256個字節(jié),2是post的數(shù)據(jù)長度在websParseRequest(wp)函數(shù)中得到,也就是說如果一個連接首次調(diào)用websGetlnput()函數(shù),應該執(zhí)行的是==0的那條分支。下面試著走一個流程,當websGetlnput()函數(shù)接收上例post頭時,會怎么處理。首先,程序會進入==0分支,接著會進入socketGets()函數(shù),我們在這個函數(shù)里去走一圈:①socketGets()函數(shù)從socket中讀取一行,然后返回,如現(xiàn)在讀到的是:POST/goform/formTestHTTP/1.1明顯程序?qū)⒅苯幼叩健ㄝ敵觯哼@里,并返回1,websGetInput()函數(shù)的上層調(diào)用函數(shù)websReadEvent()開始進入狀態(tài)機WEBS_BEGIN進行處理,分析post頭的第一行,分析成功將狀態(tài)轉(zhuǎn)到WEBS_HEADER,這時第二次調(diào)用websGetInput()。這里wp結(jié)構(gòu)除了state變量變了,其他都沒變,所以len還是0,還是調(diào)用socketGets()函數(shù)從socket中讀取一行,我們這都假設讀成功,先不想不成功的事,現(xiàn)在我們到WEBS_HEADER狀態(tài)機,把讀到的數(shù)據(jù)放入wp->header緩存變量中,這樣一直讀到Authorization:BasicYWRtaW46YWRtaW4=這時,wp->header緩存中存放了除第一行以外的head,好,到這時,websReadEvent()還會再調(diào)用一次websGetInput(),我們看這回會有什么情況。另外先說下WEBS_HEADER狀態(tài)機中為什么會有ringqPutStr(&wp->header,T(""));這一句,是因為在socketGets()函數(shù)以””為一行結(jié)束標志來返回這一行,但是并沒有包括””,所以在這里總是會加上一個以便后面的程序做分析。接著讀,還是走到socketGets()函數(shù),這時將會讀到””這一行,在socketGets()函數(shù)中這樣處理:因為’’是不加入緩存的,當讀到’’時,程序這樣處理:if(c==''){len=ringqLen(lq);if(len>0){*buf=ballocAscToUni((char*)lq->servp,len);}else{*buf=NULL;}ringqFlush(lq);returnlen;}這里用得很巧妙,因為'’是不加入緩存,所以len=ringqLen(lq將為0,這時理所當然返回0了,也就是讀完head了,我們看當websGetInput()收到socketGets()的0返回值時,會怎么樣處理。④按上圖,程序就會走到wp->state這個條件分支,當前狀態(tài)是WEBS_HEADER,所以會執(zhí)行websParseRequest()函數(shù),這個函數(shù)會盡情的分解這個頭文件,而馬上要起到作用的是在分解時處理的一個變量:wp->flags|=WEBS_CLEN。這是根據(jù)頭中的Content-Length:116得到的。如果頭中沒有這行,會怎么辦?那么首先wp->flags中不會有WEBS_CLEN這一位,并且wp->clen也不會被初始化。下一步進入wp->flags條件,就是上圖①中的入口,程序如下:if(wp->flags&WEBS_POST_REQUEST){if(wp->flags&WEBS_CLEN){wp->state=WEBS_POST_CLEN;clen=wp->clen;}else{wp->state=WEBS_POST;clen=1;}if(clen>0){return0;}return1;}如果是WEBS_POST_REQUEST,則繼續(xù)到條件wp->flags,如果是WEBS_CLEN(如果是標準http頭,肯定是有這個的),就把wp->state=WEBS_POST_CLEN,然后置clen=wp->clen,注意,這里clen可能是0,Content-Length:0如果wp->flags中沒有WEBS_CLEN這一位,則設置wp->state=WEBS_POST和clen=1,接著根據(jù)clen的值大于0返回0,上面說了有可能等于零的情況,那么會返回1(表示沒有數(shù)據(jù)可讀了)。我們先看websGetlnput()返回0給上級函數(shù)websReadEvent()時的情況。在websReadEvent()中,如果websGetInput()返回0,則表明還有數(shù)據(jù)沒讀完,這時將會再次調(diào)用websGetInput(),這時程序會走進if(wp->state==WEBS_POST_CLEN){len=(wp->clen>WEBS_SOCKET_BUFSIZ)?WEBS_SOCKET_BUFSIZ:wp->clen;}else{len=0;},那么這里條件len將會>0,于是我們走進上圖中的len>0分支,調(diào)用socketRead()函數(shù),這里不討論出錯情況,socketRead()函數(shù)將讀完最大長度不超過WEBS_SOCKET_BUFSIZ的post數(shù)據(jù),然后websGetInput()返回1,我們又回到websReadEvent()函數(shù)。在websReadEvent()函數(shù)我們進入WEBS_POST_CLEN狀態(tài)機,在這個處理模塊將讀完整個post數(shù)據(jù),然后送websUrlHandlerRequest(wp)函數(shù)進行處理。這時websReadEvent()函數(shù)算是功得圓滿了,置done為1退出函數(shù)。上面就是讀客戶端post數(shù)據(jù)并且該數(shù)據(jù)標有長度情況下的整個流程。在沒有長度的情況下,如果有瀏覽器訪問,除非瀏覽器有bug,正常是不會出現(xiàn)這種情況的。沒長度時len=0,websGetInput()進入socketGets()那分支,然后一直讀,讀到出錯(nbytesvO)或者是讀完(nbytes=0)為止,我們先看<0那個分支,如果小于0就到條件EOF,如果是socket讀完(走Y那個公支),那也就是正常結(jié)束情況,于是進入條件wp->state,如果是WEBS_POST狀態(tài)機,則調(diào)用websUrlHandlerRequest(wp)函數(shù)進行處理,也就是在這里走完了post沒有l(wèi)en情況下的流程。而我們再看回頭看websReadEvent()函數(shù)中WEBS_POST狀態(tài)機的功能只是把數(shù)據(jù)讀到wp->header中。如果不是在WEBS_POST狀態(tài)機,程序?qū)⒄{(diào)用websDone(wp,0)函數(shù)直接把該連接關閉,為什么呢?如果程序能走到這里,又不是WEBS_POST,那更不可能是WEBS_POST_LEN狀態(tài),那只有可能是WEBS_BEGIN或WEBS_HEADER狀態(tài),WEBS_BEGIN只讀第一行POST/goform/wirelessAdvaneedHTTP/1.1而讀這一行是不會出現(xiàn)EOF狀態(tài)的,1是如果下面還有數(shù)據(jù),出現(xiàn)EOF就說明這個head有問題,2是如果下面沒有數(shù)據(jù),應該是以””結(jié)尾的,如③所分析,socketGets()返回0,websGetInput()不會進入小于0的分支,所以這里程序的處理是把這個連接關閉了。if(wp->state==WEBS_POST){websUrlHandlerRequest(wp);}else{websDone(wp,0);}現(xiàn)在websGetInput()函數(shù)還有一個分支沒有分析,就是在④的情況下,沒有進入上圖①的接口,這種情況下會發(fā)生什么?首先請看下面的http頭:GET/forms.aspHTTP/1.1Accept:image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/*Accept-Language:zh-cnAccept-Encoding:gzip,deflateUser-Agent:Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1;.NETCLR2.0.50727;CIBA)Host:0Connection:Keep-Alive程序不進入①是因為wp->flags&WEBS_POST_REQUEST這個條件不成立,所以我給出上面的一個GET頭,這時wp->flags中應該在WEBS_BEGIN狀態(tài)機下的websParseFirst()函數(shù)中沒有被設置為WEBS_POST_REQUEST,這里不得不插入一段websParseFirst()函數(shù)中的代碼說明情況:if(gstrcmp(op,T("GET"))!=0){if(gstrcmp(op,T("POST"))==0){wp->flags|=WEBS_POST_REQUEST;}elseif(gstrcmp(op,T("HEAD"))==0){wp->flags|=WEBS_HEAD_REQUE
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025江蘇省安全員《A證》考試題庫
- 靈芝種植產(chǎn)業(yè)基地項目可行性研究報告-靈芝市場需求持續(xù)擴大
- 廣州中醫(yī)藥大學《試劑生產(chǎn)工藝》2023-2024學年第一學期期末試卷
- 2025青海省建筑安全員-B證考試題庫及答案
- 廣州醫(yī)科大學《哲學通論》2023-2024學年第一學期期末試卷
- 2025遼寧建筑安全員考試題庫
- 2025年江蘇建筑安全員考試題庫及答案
- 2025年-江蘇省安全員《B證》考試題庫及答案
- 《FOOD中國飲食文化》課件
- 【語文課件】冀中的地道戰(zhàn)課件
- 你比我猜成語
- 異質(zhì)結(jié)完整分
- 膿毒癥1小時bundle質(zhì)量控制
- 第7講 高斯光束的聚焦和準直課件
- 骨科患者術后疼痛管理的新進展
- 小學生三好學生競選演講稿PPT幻燈片
- 01S201室外消火栓安裝圖集
- 蒸餾酒及配制酒衛(wèi)生檢驗原始記錄
- 高一英語外研版必修一(2019)Unit 1 Period 8 Writing-Writing a journal entry(學案)
- 鉆井HSE作業(yè)風險控制
- S7-200SMARTPLC應用技術PPT完整全套教學課件
評論
0/150
提交評論