Tomcat原理学习---连接器Connector(一)

包org.apache.catalina.connector里边的属性文件包含了该包所有的类抛出的所有错误信息。
org.apache.catalina.util.StringManage类的实例处理每个属性文件

本章三大模块:connector、startup、core


startup模块:BootStrap类
connector模块的类分5组:
-连接器(HttpConnector)和它的支撑类(HttpProcessor)
-指代HTTP请求的类(HttpRequest)和它的辅助类
-指代HTPP响应的类(HttpResponse)和它的辅助类
-Facade类(HttpRequestFacade和HttpResponseFacade)
-Constant类
core模块:ServletProcess、StaticResourceProcessor


第二章的HttpServer类的工作,在本章:
等待HTTP请求的工作交给HttpConnector实例
创建请求和响应对象的工作交给了HttpProcessor实例


bootstrap类:启动应用程序


本应用程序运行前:
1、启动应用程序
2、连接器
3、创建一个HttpRequest对象
4、创建一个HttpResponse对象
5、静态资源处理器和servlet处理器
6、运行应用程序


Tomcat的默认连接器和我们的连接器使用SocketInputStream类来从套接字的InputStream中读取字节流。一个SocketInputStream实例对从套接字的getInputStream方法中返回的java.io.InputStream实例进行包装。
SocketInputStream类2个重要的方法:readRequestLine、readHeader
readRequestLine:返回HTTP请求的第一行,包括URI,方法,HTTP版本。 readHeader被调用前,readRequestLine必须只被调用一次。返回值是一个HttpRequestLine实例。
readHeader:获取一个头部的名/值对,并且应该被重复的调用直到所有的头部被读取到,返回值是一个HttpReader对象。




HttpConnector的run方法:(类似于第二章的await方法)
-等待HTTP请求
-为每个请求创建个HttpProcessor实例
-调用HttpProcessor的process方法
HttpProcessor的process方法:
-创建一个HttpRequest对象
-创建一个HttpResponse对象
-解析Http请求的第一行和头部,并放到HttpRequest对象
-解析HttpRequest和HttpResponse对象到一个ServletProcessor或者StaticResourceProcessor。
HttpProcessor类中的私有方法:
parseRequest、parseHeaders、normalize都是用来填充HttpRequest的


程序员可以从HTTP请求中获取头部、cookie和参数,这三种类型的值被存储在下面几个引用变量中:
protected HashMap headers = new HashMap();
protected ArrayList cookies = new ArraryList();
protected ParameterMap parameters = null;




Http请求的解析:
1、读取套接字的输入流
2、解析请求行
3、解析头部
4、解析cookies
5、获取参数



1、读取套接字的输入流
SocketInputStream input = null;
OutputStream output = null;
try{


input = new SocketInputStream(socket.getInputStream(),2048);
...


}
2、解析请求行
HttpProcessor的process方法调用私有的parseRequest来解析请求行。
例如:
GET /myApp/ModernServlet?userName=zhangsan&password=psw HTTP/1.1
请求行的第二部分是URI加上一个查询字符串。
URI:/myApp/ModernServlet
?后面的是查询字符串:
userName=zhangsan&password=psw
参数名/值对:userName/zhangsan和password/psw
参数名jsessionid是用来携带一个会话标识符,常被作为cookie来嵌入,当浏览器的cookie被程序员禁用时,会话标识符可以嵌入到查询字符串去。


HttpProcessor类的parseRequest方法:
调用了SocketInputStream类的readRequestLine方法
以下是parseRequest获得请求行的方法、URI和协议:
String method = new String(requestLine.method,0,requestLine.methodEnd);
String uri = null;
String protocol = new String(requestLine.protocol,0,requestLine.protocolEnd);




----String(a,b,c)---requestLine.indexOf("?")-----是什么意思?

如果URI后面有查询符,会被一个?分隔开来。因此,parseRequest试图首先获取查询字符串,并调用setQueryString方法来填充HttpRequest对象:
int question = requestLine.indexOf("?"); 
if (question >= 0) { 
   request.setQueryString(new String(requestLine.uri, question + 1, 
   requestLine.uriEnd - question - 1)); 
   uri = new String(requestLine.uri, 0, question); 

else { 
   request.setQueryString (null); 
   uri = new String(requestLine.uri, 0, requestLine.uriEnd); 
}


不过,大多数情况下,URI指向一个相对资源,URI还可以是一个绝对值,就像下面所示: 
 
http://www.brainysoftware.com/index.html?name=Tarzan 
   parseRequest方法同样也检查这种情况: 
if (!uri.startsWith("/")) { 
   int pos = uri.indexOf("://"); 
   if (pos != -1) { 
       pos = uri.indexOf('/', pos + 3); 
       if (pos == -1) { 
           uri = ""; 
       } 
       else { 
           uri = uri.substring(pos); 
       } 
   } 
}


  接下来还要查询jsessionid是否在查询字符串里面,而不是在cookie里面,若有,则传递 true 给 request 的 setRequestSessionURL 方法。否则,传递 false 给
setRequestSessionURL方法并传递null给 setRequestedSessionURL方法。 
    到这个时候,uri的值已经被去掉了jsessionid。


    normalize方法:用于纠正“异常”的URI。
    例如:任何的\的出现都会被/替代。
    normalize将会返回纠正后的URI,若URI不能纠正的话,会返回null。parseRequest会在方法的最后抛出异常。


    3、解析头部
    一个HTTP头部是用HttpHeader类来代表的。
        你可以通过使用类的无参数构造方法构造一个HttpHeader实例。 
    一旦你拥有一个HttpHeader实例, 你可以把它传递给SocketInputStream的readHeader
方法。假如这里有头部需要读取,readHeader方法将会相应的填充HttpHeader对象。
假如再也没有头部需要读取了, HttpHeader实例的nameEnd和valueEnd字段将会置零。 
  为了获取头部的名称和值,使用下面的方法: 
  
String name = new String(header.name, 0, header.nameEnd);  
  String value = new String(header.value, 0, header.valueEnd);  
 
  一旦你获取到头部的名称和值,你通过调用HttpRequest对象的addHeader方法来把它加入
headers这个HashMap中: 
request.addHeader(name, value); 
   一些头部也需要某些属性的设置。例如,当 servlet 调用 javax.servlet.ServletRequest
的getContentLength方法的时候, content-length头部的值将被返回。而包含cookies的cookie
头部将会给添加到cookie集合中。


4、解析Cookies
Cookies 是作为一个 Http 请求头部通过浏览器来发送的。这样一个头部名为"cookie"并且
它的值是一些 cookie 名/值对。
Cookie: userName=budi; password=pwd; 


Cookies的解析是通过org.apache.catalina.util.RequestUtil的parseCookieHeader方法来处理的。这个方法接受cookie头部并返回一个javax.servlet.http.Cookie数组。


5、获取参数
参数可以在查询字符串或者请求内容里面找到。
用户使用get方法请求servlet的话,则在查询字符串找到。
用户使用post方法,则在请求内容中找到。
所有的名/值对,都会存储在HashMap中,可以通过HttpServletRequest的getParameterMap获得参数名/值。


类ParameterMap继承java.util.HashMap,并使用一个布尔变量locked。当locked为"false"的时候,名/值对可以添加、更新或者移除。







(创建HttpResponse对象
HttpResponse 类实现了 javax.servlet.http.HttpServletResponse。跟随它的是一个叫做HttpResponseFacade的facade类。
在第2章中,你使用的是一个部分实现的HttpResponse类。例如,它的getWriter方法,在它的其中一个print方法被调用的时候,返回一个不会自动清除的java.io.PrintWriter对象。
以下将会修复这个问题。)


总结 
在本章中,你已经知道了连接器是如何工作的。建立起来的连接器是Tomcat4的默认连接器
的简化版本。正如你所知道的,因为默认连接器并不高效,所以已经被弃用了。例如,所有的
HTTP 请求头部都被解析了,即使它们没有在 servlet 中使用过。因此,默认连接器很慢,并且
已经被 Coyote 所代替了。这里的,HttpConnector在它自身的线程中运行。但是,在处理下一个请求之前,它必须等待当前处理的HTTP请求结束。HttpProcessor类的process方法是同步的。因此,在接受另一个请求之前,它的run方法要等待process方法运行结束。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值