Tomcat NIO源代码分析(三) -- Protocol和Processor

现在请求到了Protocol(Http11NioProtocol)的#process()方法了,由于方法较长,很多代码没有列出:

     public  SocketState process(NioChannel socket)  {
        
//  得到Processor
        Http11NioProcessor processor  =  connections.remove(socket);
        
try   {
            
if  (processor  ==   null {
                processor 
=  recycledProcessors.poll();
            }

            
if  (processor  ==   null {
                processor 
=  createProcessor();
            }


            
//  配置processor是否SSL:略
            ......

            
//  重要:调用Processor的#process()方法
            SocketState state  =  processor.process(socket);

            
//  对长连接的支持:略
             if  (state  ==  SocketState.LONG)  {
                ......
            }

            
if  (state  ==  SocketState.LONG  ||  state  ==  SocketState.ASYNC_END)  {
                
//  Already done all we need to do.
            }
  else   if  (state  ==  SocketState.OPEN)  { //  一般的keep-alive的请求都回到这里
                
//  开始回收Processor
                release(socket);
                
//  如果keep-alive,那么将SocketChannel继续加到Poller中等待
                socket.getPoller().add(socket);
            }
  else   {
                
//  回收Processor
                release(socket);
            }

            
return  state;

        }
  catch (XXXException) {
            
//  略过异常处理
            ......
        }

        
        
//  做一些回收工作
        connections.remove(socket);
        processor.recycle();
        recycledProcessors.offer(processor);
        
return  SocketState.CLOSED;
    }


这里很明显,最重要的是对Processor的#process()的调用,直接上代码,当然,方法太长也略过了很多部分。另外对请求的byte[]的解 析就不上代码了,太长了,主要的方式就是byte[]循环的方式,这也是为了提高效率的考虑,毕竟使用字符串和byte相比还是要慢的。

     public  SocketState process(NioChannel socket)  throws  IOException  {
        RequestInfo rp 
=  request.getRequestProcessor();
        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);

        
//  Setting up the socket
         this .socket  =  socket;
        inputBuffer.setSocket(socket);
        outputBuffer.setSocket(socket);
        inputBuffer.setSelectorPool(endpoint.getSelectorPool());
        outputBuffer.setSelectorPool(endpoint.getSelectorPool());

        
//  Error flag
        error  =   false ;
        keepAlive 
=   true ;
        comet 
=   false ;

        
long  soTimeout  =  endpoint.getSoTimeout();
        
int  keepAliveTimeout  =  endpoint.getKeepAliveTimeout();

        
boolean  keptAlive  =   false ;
        
boolean  openSocket  =   false ;
        
boolean  recycle  =   true ;
        
final  KeyAttachment ka  =  (KeyAttachment) socket.getAttachment( false );

        
while  ( ! error  &&  keepAlive  &&   ! comet  &&   ! isAsync()  &&   ! endpoint.isPaused())  {
            
//  always default to our soTimeout
            ka.setTimeout(soTimeout);
            
//  Parsing the request header
             try   {
                
if  ( ! disableUploadTimeout  &&  keptAlive  &&  soTimeout  >   0 {
                    socket.getIOChannel().socket().setSoTimeout((
int ) soTimeout);
                }

                
//  这里将Socket的数据读入到读缓冲区,nRead = socket.read(socket.getBufHandler().getReadBuffer());
                
//  并且将协议和请求的URI解析出来
                 if  ( ! inputBuffer.parseRequestLine(keptAlive))  {
                    
//  略过非正常情况的处理
                }

                keptAlive 
=   true ;
                
//  这一步是解析请求的Header,Tomcat的解析是直接基于byte[]去逐个循环的,可以好好学下
                 if  ( ! inputBuffer.parseHeaders())  {
                    
//  略过非正常情况的处理
                }

                request.setStartTime(System.currentTimeMillis());
                
if  ( ! disableUploadTimeout)  {
                    socket.getIOChannel().socket().setSoTimeout(timeout);
                }

            }
  catch (XXXException) {
                
//  略过异常处理
                ......
            }


            
if  ( ! error)  {
                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
                
try   {
                    
//  设定请求处理的一些Filters
                    prepareRequest();
                }
  catch (XXXException) {
                    
//  略过异常处理
                    ......
                }

            }


            
if  (maxKeepAliveRequests  ==   1 )
                keepAlive 
=   false ;
            
if  (maxKeepAliveRequests  >   0   &&  ka.decrementKeepAlive()  <=   0 )
                keepAlive 
=   false ;

            
//  Process the request in the adapter
             if  ( ! error)  {
                
try   {
                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
                    
//  这里就是调用CoyoteAdapter去继续请求了,此时请求会脱离Connctor层进入Engine层了
                    
//  进入Tomcat请求处理PipeLine的下一段管道了
                    adapter.service(request, response);

                    
if  (keepAlive  &&   ! error)  //  Avoid checking twice.
                        error  =  response.getErrorException()  !=   null
                                
||  statusDropsConnection(response.getStatus());
                    }

                    
//  长连接的支持:略
                    ......

                }
  catch (XXXException) {
                    
//  略过异常处理
                    ......
                }

            }


            
//  收尾和回收工作:略

        }
//  while

        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
        
if  (error  ||  endpoint.isPaused())  {
            recycle();
            
return  SocketState.CLOSED;
        }
  else   if  (comet  ||  isAsync())  {
            
return  SocketState.LONG;
        }
  else   {
            
if  (recycle)  {
                recycle();
            }

            
//  return (openSocket) ? (SocketState.OPEN) : SocketState.CLOSED;
             return  (openSocket)  ?  (recycle  ?  SocketState.OPEN : SocketState.LONG) : SocketState.CLOSED;
        }


    }

 

这段代码有分4个部分需要关注下。
 (1) 对inputBuffer的#parseRequestLine()的调用,这里主要就是读入Socket的数据并且解析出请求的URI;
 (2) 对inputBuffer的#parseHeaders()的调用,这里就是读取请求中的请求头了;
 (3) #prepareRequest()的调用,这里主要是对前两步得到的数据进行分析使用,构建处理请求的上下文属性,并且如果请求的transfer- encoding域有值,需要配置相应的Filter去处理。默认有 IdentityInputFilter,ChunkedInputFilter,VoidInputFilter,BufferedInputFilter 四种;
 (4) 对CoyoteAdapter的#service()的调用,这里就准备进入PipeLine的下一段管道了。

全文完。

你可能感兴趣的:(apache,tomcat,socket,UP,Comet)