《深入剖析tomcat》读书笔记2

《深入剖析tomcat》读书笔记准备写四篇,这篇是第二篇,分析默认连接器,对应书籍的第四章。第三篇分析容器,第四篇来个纵向总结,顺便回答第一篇开头提出的问题。

第四章  Tomcat默认连接器

1. Tomcat连接器

Tomcat连接器是一个独立模块,可以被插入到servlet容器中。连接器有很多种,coyote,mod_jk等等。Tomcat使用的连接器必须满足下面要求:

(1)      实现Connector接口;

(2)      创建request对象;

(3)      创建response对象;

2.连接器和servlet容器如何一起工作?

         连接器首先和一个container关联,然后等待Http请求,创建request对象、response对象。然后调用container接口的invoke()方法,把request对象和response对象传递给servlet容器。servlet容器会载入相应的servlet类,调用其service()方法,管理session对象等等。

3.Http1.1新特性

          Http1.1新特性引入了3个新特性:持久链接(keep-alive)、块编码、状态码100。

a.持久链接

         持久链接定

         HTTP持久连接是使用同一个TCP连接来发送和接收多个HTTP请求/应答,而不是为每一个新的请求/应答打开新的连接的方法。

         为什么使用持久链接?

         非持久连接每请求一个资源都要建立HTTP链接,开销太大。如果一个页面有10张图片,使用非持久链接至少总共建立11个TCP链接来完成这个请求1

         持久链接为使用同一个链接来下载所有资源,节省资源。具体优势如下2

1.较少的CPU和内存的使用(由于同时打开的连接的减少了);

2.允许请求和应答的HTTP管线化;

3.降低网络阻塞 (TCP连接减少了);

4.减少了后续请求的延迟(无需再进行握手);

5.报告错误无需关闭TCP连接;

b.块编码

       块编码定义

       输编码是超文本传输协议一种数据传输机制,允许HTTP网页服务器发送给客户端应用( 通常是网页浏览器)的数据可以分成多个部分。

       为什么使用块编码?

1. 对于动态生成的内容来说,在内容创建完之前是不可知的

2. 分块传输编码允许服务器在最后发送消息头字段

3. 分块编码有利于一边进行压缩一边发送数据,而不是先完成压缩过程以得知压缩后数据的大小

c.状态码100的使用

       当客户端准备发送一个较长的请求体,而不确定服务器是否会接受的时候,可以在请求体之前发送:Expect: 100-continue。若服务器可以接受并处理该请求,可以发送相应:

HTTP/1.1 100continue。

       为什么引入状态码100?

       如果客户端发送一个较长的请求体最后却被服务器拒绝接受时,发生较大浪费。

总的说来,3个特性的引入,目的都是让web服务器更节省资源开销,更快地响应速度。

4.HttpConnector类

         HttpConnector做的事情:

a.    创建服务器套接字

通过一个服务器套接字工厂获得服务器套接字。

b.    维护HttpProcessor实例

         HttpProcessor的作用已经在第三章提过了,不再重复。HttpConnector通过维护一个HttpProcessor对象池来避免每次为新请求创建HttpProcessor对象。维持HttpProcessor对象池策略如下:a.对象池大小由minProcessor和maxProcessor来确定。如果请求的数目超过了HttpProcessor的实例,那么创建更多的HttpProcessor对象,但是保证会不超过maxProcessor大小。b. 对象池的数据结构是栈。

c.    提供http请求服务

从对象池栈中弹出一个HttpProcessor对象,将接收到的socket传给这个HttpProcessor对象,进行处理。这里HttpProcessor在独立的线程里面,所以connector会立即返回,再次接受请求。

5.   HttpProcessor类

         HttpProcessor对象和HttpConnector对象的协作方式是这章的精华。

直接贴代码

public class HttpConnector implements Connector, Runable{
 
    public void run(){
       while(!loop){
           //...省略
           ServerSocket serverSocket = new(...)
           Socket socket = setverSocket.accept();
           HttpProcessor httpProcessor = createHttpProcessor(this); //从processor池中读取,如果无且小于max,则创建
           if (httpProcessor==null) //processor池中无实例
                socket.close();
           httpProcessor.assign(socket);
    }
   }
}
 
public class HttpProcessor implements Runable{
 
    public void run(){
        while(!loop){
            Socket socket = await();
            if (socket == null){
                continue;
            }
            //...
            process(socket);
            connector.recycle(this);
            synchronized (threadSync){
                threadSync.notifyAll();
            }
     }
    }
    
    private synchronized void assign(Socket socket){
        while (available){
            wait();
        }
        //...
        this.socket = socket;
        available = true;
        notifyAll(); //唤醒await处理
    }
    
    private synchronized Socket await(){
        while (!available){
            wait();
        }
        Socket socket = this.scoket;
        available = false;
        notifyAll(); //告诉assign,处理完成,可以接收下一个
        return socket;
    }
   
}

HttpProcessor有2个方法assign(Socketsocket)和await()。理解这两个方法的协作实际上就理解了HttpProcessor对象和HttpConnector对象的协作方式。

5.1assign()和await()做的事情

assign(Socketsocket)由HttpConnector调用,HttpConnector通过

Socket socket = setverSocket.accept();

接受到一个socket,立马调用httpProcessor.assign(socket),将接收到的socket扔给httpProcessor处理。

await()的实现,什么都没有做,就在等待socket。await()运行在HttpProcessor的线程中。

5.2assign()和await()如何协作

HttpProcessor实现了runable接口,和HttpProcessor工作在不同的线程空间。通过修改available变量来协作。available变量表示有没有socket:有socket,available=true;没有socket,available=fasle。assign()和await()方法共享scoket和available

HttpProcessor线程启动后,执行await()方法。此时available=false,表示没有socket,那么wait();把CPU时间片让给其它线程。HttpConnector线程也在运行中,在没有socket链接的时间里,该线程一直阻塞在了Socket socket = serverSocket.accept();这个方法里面。在某个时刻,setverSocket.accept()接收到了socket,立即执行到调用了HttpProcessor的assign()方法。assign()方法中,available=false,直接做:

available= true;   //修改available true,表示有socket

notifyAll(); //唤醒await处理

         此时,cpu时间片切换到了HttpProcessor线程。又开始执行await()方法。

Socket socket = this.scoket;   
available = false;
notifyAll(); //告诉assign,处理完成,可以接收下一个。此时,便可以执行process(socket);       
5.3  assign()和await()如何协作背后

assign()和await()分别被connector和processor调用。connector负责提供socket,processor在等待socket其实就是

上生产者—消费者模型。通过available变量来表明是否有socket。不然,消费者processor的process()方法执行的时候,

发现都没有socket。生成者connector在分配socket的时候,发现有socket还没有处理完,绝不分配Socket。他们通过

修改avaible变量来通知对方是否有资源socket,进行通信。


1.      10.1.5 HTTP非持久连接和持久连接:http://book.51cto.com/art/201108/282330.htm
2.      HTTP持久链接
http://zh.wikipedia.org/wiki/HTTP%E6%8C%81%E4%B9%85%E9%93%BE%E6%8E%A5


 

你可能感兴趣的:(《深入剖析tomcat》读书笔记2)