Tomcat源码解析(3)

默认连接器

   上一节的连接器可以正常工作,经过修改还可以实现更多功能。这里介绍Tomcat的默认连接器(已被Coyote取代)。

   连接器是一个独立的模块,可以被插入到servlet容器中。

   Tomcat的连接器必须满足:1.实现org.apache.catalina.Connector接口  2.负责创建org.apache.catalina.Request接口的request对象  3.负责创建org.apache.catalina.Reponse接口的reponse对象

   连接器,通过调用它的invoke方法,将request和response传给servlet,并载入servlet类,调用service方法。

   与上节相比,多了很多优化的方法。比如:使用一个对象池来避免频繁创建对象带来的性能损耗。使用字符数组来代替字符串。

   连接器实现了所有HTTP1.1的全部新特性。

1.1的新特性

   持久连接:之前。无论何时连接服务器,将请求的资源返回后就断开连接。但网页上包含一些其他资源的,这一再次连接,开销很大。持久连接后,下载页面后,等待客户端请求的相关资源下载。使用同一个连接。

   connection : keep-alive

   块编码:持久连接后,服务器可以从多个资源发送流,客户端使用这一个连接发送多次请求。这样,发送方必须在每个请求或响应添加“content-length”头信息。接收方才知道如何解释字节信息。

   1.0可以不写头信息,尽管在响应内容写,写完关闭。而客户端,接受,直到读方法返回-1。

   1.1使用一个“transfer-encoding”特殊请求头。指明字节流会分块发送。每个块后面会跟一个回车/换行符。

     例如:   1D\r\n   +内容   1d是29,指明内容29个字节。    9\r\n + 内容

   状态码100的使用:当客户端发送一个较长请求体,不确定服务器是否接受。会加上 Expect : 100-continue  ,以检测是否服务器会接受,较长请求体。

   服务接受到之后,如果可以接受,则返回 HTTP/1.1  100  Continue 响应头。


org.apache.catalina.Connector接口

   关键的方法:set,getContainer()、createRequest()、createResponse()

   setContainer()用于将连接器和某个servlet相关联(一对一的关系),get,返回关联的servlet。


org.apache.catalina.connector.http.HttpConnector实现了接口。(Lifecycle接口,维护每个实现了该接口的Catalinna组建的生命周期,创建后就应该调用initialize()与start())

   1.创建服务器套接字

        initialize()会调用一个私有方法open()(从ServerSocketFactory工厂取),返回一个ServerSocket实例。

   2.维护HttpProcessor实例。

        HttpConnector维护一个它的实例池,避免每次都创建。private Stack processors = new Stack();

        创建的实例数量,由minProcessors和maxProcessors变量决定的。默认是5和20。如果超过最大限定数值。那么引入的HTTP请求被忽略。设置max为负数,则会不断的新建实例。

    3.提供HTTP请求服务

        该类,主要业务逻辑在run方法里。对于每个http请求,都会调私有方法createProcessor()获得一个实例。达到最大上限返回null,之后关闭套接字,不处理。

        获得实例之后,将套接字传入,processor.assigin(socket),之后就开始解析。


HttpProcessor类

    上一节已经有基本实现。他是一个线程类。在接收到socket就直接返回。不要等待解析完成。那么assigin需要异步处理。

    

run(){
   while(!stop){
   //接受套接字
     Socket socket = await();//会阻塞知道获取新的socket(也就是说,直到HttpConnector调HttpProcessor的assigin方法之前)
     if(socket==null)  
       continue;
     //进行处理
     process(socket);
    //调用连接器的recycle(),将当前的HttpProcessor实例压回栈中
    connector.recycle(this);
  }
}

void recycle(HttpProcessor processor){
   processors.push(processor);
}

await会阻塞,他和assigin()不是在同一个线程的。assign()是zai HttpConnector()的run方法中(连接线程),await是在HttpProcessor的run方法中(处理器现场)。

  await(),我们通过available这个boolean变量和notifyAll()来实现,唤醒。

  

Synchronized void assign(Socket socket){
  //如果那边在等待 available,值为false。等待这边变true
  while(available){
     wait();
  }
  this.socket = socket;
  available= true;
  notifyAll();
}

Synchronized Socket await(){
 //如果为False,则需要等待,等待socket传过来,该变量则为true
  while(!available){
     wait();
  }
  Socket socket = this.socket;   //这里使用局部变量,是因为,在当前socket处理完之前,可以继续接受对象。
  available = false;
  notifyAll();
  return socket;
}

   处理请求。

   process();    通过boolean ok = true;来表示处理过程中是否有错误。boolean finishResponse = true。表示是否应该调用Response接口的finishResponse()方法。  还有keepAlive是否持久连接。stopped表示HttpProcessor实例是否被连接器终止。

   调用parseConnection()、parseRequest()和parseHeaders()解析引入的HTTP请求。

   parseHeaders(),获取请求使用的协议,如果是HTTP1.0则将keepAlive设置为false。 如果发现“Expect: 100-continue”,则parseHeaders()中,将设置sendAck为true。

  中间发生任何异常都会将ok变为false,之后完成解析,将request和response传给servlet,最后如果finishResponse 为true,调用request和response的finishResponse 方法,再将结果发送到客户端。

   最后request.recycle()和response.recycle()将对象收回。


   解析连接。

 parseConnectionb() 会从套接字获取Internet地址,赋值给HttpRequestImpl对象。 还要检查是否使用代理

   

private void parseConnection(Socket socket){
   if(debug >= 2)
      log();
   //将地址赋值给request
    ((HttpRequestImpl)request).setInet(socket.getInetAddress());
   //如果使用代理  
     if(proxyProt != 0)
         request.setServerProt(proxyPort);
     else
        request.setServerProt(serverPort);

     request.setSocket(socket);
}


    解析请求头。

    parseHeaders()方法使用,org.apache.catalina.conncetor.http包中的HttpHeader类(代表一个HTTP请求头),和DefaultHeader类。

    HttpHeader类,使用字符数组,避免代价高昂的字符串操作

    DefaultHeader类,是一个final类,包含字符数组形式的标准HTTP请求。

          static final char[] AUTHORIZATION_NAME ="authorization".toCharArray();

   



   


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值