随笔-9  评论-3  文章-0  trackbacks-0
现在请求到了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的下一段管道了。

全文完。

posted on 2010-12-09 09:47 臭美 阅读(2026) 评论(0)  编辑  收藏 所属分类: Tomcat

只有注册用户登录后才能发表评论。


网站导航: