目標:在這篇文章希望搞明白http請求到tomcat后是怎么由連接器轉交到容器的?
? ? ? 在上一節里已經啟動了一個HttpConnector線程,并且也啟動了固定數量的HttpProcessor線程。HttpConnector用來等待http連接,得到http連接后交給其中的一個HttpProcessor線程來處理。接下里具體看一下HttpConnector是怎么得到連接得,以及HttpProcessor是怎么處理的。當啟動了HttpConnector線程后(在上一節已經知道怎么啟動了),便在它的run方法里面循環等待:
- public ? void ?run()?{??
- ???? //?Loop?until?we?receive?a?shutdown?command ??
- ???? while ?(!stopped)?{??
- ???????? //?Accept?the?next?incoming?connection?from?the?server?socket ??
- ????????Socket?socket?=? null ;??
- ???????? try ?{??
- ????????????socket?=?serverSocket.accept();??
- ???????????? if ?(connectionTimeout?>? 0 )??
- ????????????????socket.setSoTimeout(connectionTimeout);??
- ????????????socket.setTcpNoDelay(tcpNoDelay);??
- ????????}? catch ?(AccessControlException?ace)?{??
- ????????????log( "socket?accept?security?exception" ,?ace);??
- ???????????? continue ;??
- ????????}? catch ?(IOException?e)?{??
- ???????????? try ?{??
- ???????????????? //?If?reopening?fails,?exit ??
- ???????????????? synchronized ?(threadSync)?{??
- ???????????????????? if ?(started?&&?!stopped)??
- ????????????????????????log( "accept?error:?" ,?e);??
- ???????????????????? if ?(!stopped)?{??
- ????????????????????????serverSocket.close();??
- ????????????????????????serverSocket?=?open();??
- ????????????????????}??
- ????????????????}??
- ??????????????????
- ????????????}? catch ?(IOException?ioe)?{??
- ????????????????log( "socket?reopen,?io?problem:?" ,?ioe);??
- ???????????????? break ;??
- ????????????}? catch ?(KeyStoreException?kse)?{??
- ????????????????log( "socket?reopen,?keystore?problem:?" ,?kse);??
- ???????????????? break ;??
- ????????????}? catch ?(NoSuchAlgorithmException?nsae)?{??
- ????????????????log( "socket?reopen,?keystore?algorithm?problem:?" ,?nsae);??
- ???????????????? break ;??
- ????????????}? catch ?(CertificateException?ce)?{??
- ????????????????log( "socket?reopen,?certificate?problem:?" ,?ce);??
- ???????????????? break ;??
- ????????????}? catch ?(UnrecoverableKeyException?uke)?{??
- ????????????????log( "socket?reopen,?unrecoverable?key:?" ,?uke);??
- ???????????????? break ;??
- ????????????}? catch ?(KeyManagementException?kme)?{??
- ????????????????log( "socket?reopen,?key?management?problem:?" ,?kme);??
- ???????????????? break ;??
- ????????????}??
- ??
- ???????????? continue ;??
- ????????}??
- ??
- ???????? //?Hand?this?socket?off?to?an?appropriate?processor ??
- ????????HttpProcessor?processor?=?createProcessor();??
- ???????? if ?(processor?==? null )?{??
- ???????????? try ?{??
- ????????????????log(sm.getString( "httpConnector.noProcessor" ));??
- ????????????????socket.close();??
- ????????????}? catch ?(IOException?e)?{??
- ????????????????;??
- ????????????}??
- ???????????? continue ;??
- ????????}??
- ???????
- ????????processor.assign(socket);??
- ??
- ????}??
- ??
- ???? //?Notify?the?threadStop()?method?that?we?have?shut?ourselves?down ??
- ???
- ???? synchronized ?(threadSync)?{??
- ????????threadSync.notifyAll();??
- ????}??
- ??
- }??
- private ?Stack?processors?=? new ?Stack();??
- private ?HttpProcessor?createProcessor()?{??
- ????? synchronized ?(processors)?{??
- ????????? if ?(processors.size()?>? 0 )?{??
- ????????????? return ?((HttpProcessor)?processors.pop());? //從processors棧中彈出一個processor ??
- ?????????}??
- ????????? if ?((maxProcessors?>? 0 )?&&?(curProcessors?<?maxProcessors))?{??
- ????????????? return ?(newProcessor());??
- ?????????}? else ?{??
- ????????????? if ?(maxProcessors?<? 0 )?{??
- ????????????????? return ?(newProcessor());??
- ?????????????}? else ?{??
- ????????????????? return ?( null );??
- ?????????????}??
- ?????????}??
- ?????}??
- ??
- ?}??
接下來由processor.assign(socket); 記住這個方法是異步的,不需要等待HttpProcessor來處理完成,所以HttpConnector才能不間斷的傳入Http請求,在HttpProcessor里有兩個方法比較重要,這兩個方法協調處理了由HttpConnector傳來的socket:
- ? synchronized ? void ?assign(Socket?socket)?{??
- ??
- ???? //?Wait?for?the?Processor?to?get?the?previous?Socket ??
- ???? while ?(available)?{??
- ???????? try ?{??
- ????????????wait();??
- ????????}? catch ?(InterruptedException?e)?{??
- ????????}??
- ????}??
- ??
- ???? //?Store?the?newly?available?Socket?and?notify?our?thread ??
- ???? this .socket?=?socket;??
- ????available?=? true ;??
- ????notifyAll();??
- ??
- ???? if ?((debug?>=? 1 )?&&?(socket?!=? null ))??
- ????????log( "?An?incoming?request?is?being?assigned" );??
- ??
- }??
- ??
- ??
- private ? synchronized ?Socket?await()?{??
- ??
- ???? //?Wait?for?the?Connector?to?provide?a?new?Socket ??
- ???? while ?(!available)?{??
- ???????? try ?{??
- ????????????wait();??
- ????????}? catch ?(InterruptedException?e)?{??
- ????????}??
- ????}??
- ??
- ???? //?Notify?the?Connector?that?we?have?received?this?Socket ??
- ????Socket?socket?=? this .socket;??
- ????available?=? false ;??
- ????notifyAll();??
- ??
- ???? if ?((debug?>=? 1 )?&&?(socket?!=? null ))??
- ????????log( "??The?incoming?request?has?been?awaited" );??
- ??
- ???? return ?(socket);??
- ??
- }??
看一下HttpProcessor的run方法:
- public ? void ?run()?{??
- ??
- ??????? //?Process?requests?until?we?receive?a?shutdown?signal ??
- ??????? while ?(!stopped)?{??
- ??
- ??????????? //?Wait?for?the?next?socket?to?be?assigned ??
- ???????????Socket?socket?=?await();??
- ??????????? if ?(socket?==? null )??
- ??????????????? continue ;??
- ??
- ??????????? //?Process?the?request?from?this?socket ??
- ??????????? try ?{??
- ???????????????process(socket);??
- ???????????}? catch ?(Throwable?t)?{??
- ???????????????log( "process.invoke" ,?t);??
- ???????????}??
- ??
- ??????????? //?Finish?up?this?request ??
- ???????????connector.recycle( this );??
- ??
- ???????}??
- ??
- ??????? //?Tell?threadStop()?we?have?shut?ourselves?down?successfully ??
- ??????? synchronized ?(threadSync)?{??
- ???????????threadSync.notifyAll();??
- ???????}??
- ??
- ???}??
很明顯,在它的run方法一開始便是調用上面的await方法來等待(因為一開始available變量為false),所以HttpProcessor會一直阻塞,直到有線程來喚醒它。當從HttpConnector中調用processor.assign(socket),會把socket傳給此HttpProcessor對象,并設置available為true,調用notifyAll()喚醒該processor線程以處理socket。同時,在await方法中又把available設置成false,因此又回到初始狀態,即可以重新接受socket。
這里處理socket的方法是process(socket),主要作用有兩點,1:解析這個socket,即解析http請求,包括請求方法,請求協議等,以填充request,response對象(是不是很熟悉,在servlet和jsp開發經常用到的request,response對象就是從這里來的)。2:傳入request,response對象給和HttpConnector綁定的容器,讓容器來調用invoke方法進行處理。process方法主要的代碼如下:
- private ? void ?process(Socket?socket)?{??
- ???????????????????input?=? new ?SocketInputStream(socket.getInputStream(),??
- ??????????????????????????????????????????connector.getBufferSize());??
- ??????????????????? //解析一下連接的地址,端口什么的 ??
- ????????????????????parseConnection(socket);??
- ???????????????????? //解析請求頭的第一行,即:方法,協議,uri ??
- ????????????????????parseRequest(input,?output);??
- ???????????????????? if ?(!request.getRequest().getProtocol()??
- ????????????????????????.startsWith( "HTTP/0" ))??
- ????????????????????parseHeaders(input); //解析http協議的頭部 ??
- ????????????????????..............................................??
- ????????????????????connector.getContainer().invoke(request,?response);??
- ????????????????????.............................................??
- }??
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
