转载

【译】Tomcat如何工作<第4章:Tomcat默认连接器>

第3章中的连接器运行良好,可以完善以实现更多功能。但是,它被设计为一种教育工具,是Tomcat 4默认连接器的简介。了解第3章中的连接器是了解Tomcat 4随附的默认连接器的关键。第4章现在将讨论通过剖析Tomcat 4的默认连接器的代码来构建真正的Tomcat连接器的过程。

注意,本章中的“默认连接器”是指Tomcat 4的默认连接器。即使现在已弃用默认的连接器,而用代号为Coyote的更快的连接器代替,它仍然是一个很好的学习工具。

Tomcat连接器是一个独立的模块,可以插入到Servlet容器中。已经存在许多连接器。示例包括Coyote,mod_jk,mod_jk2和mod_webapp。Tomcat连接器必须满足以下要求:

org.apache.catalina.Connector
org.apache.catalina.Request
org.apache.catalina.Response

Tomcat 4的默认连接器的工作方式与第3章中的简单连接器相似。它等待传入的HTTP请求,创建请求和响应对象,然后将请求和响应对象传递到容器。连接器通过调用 org.apache.catalina.Container 接口的 invoke 方法将请求和响应对象传递到容器,该方法具有以下签名。

public void invoke(org.apache.catalina.Request request, org.apache.catalina.Response response);
复制代码

invoke 方法内部,容器加载servlet类,调用其 service 方法,管理会话,记录错误消息等。

默认连接器还采用了第3章的连接器中未使用的一些优化。首先是提供各种对象的池,以避免创建昂贵的对象。其次,在许多地方,它使用char数组而不是字符串。

本章中的应用程序是一个简单的容器,它将与默认连接器关联。但是,本章的重点不是这个简单的容器,而是默认的连接器。容器将在第5章中讨论。不过,简单容器将在本章结尾的“简单容器应用程序”部分中进行讨论,以显示如何使用默认连接器。

需要注意的另一点是,默认连接器实现了HTTP 1.1的所有新功能,并且能够为HTTP 0.9和HTTP 1.0客户端提供服务。要了解HTTP 1.1中的新功能,你首先需要了解这些功能,我们将在本章的第一部分中进行解释。此后,我们讨论 org.apache.catalina.Connector ,接口以及如何创建请求和响应对象。如果你了解第3章中的连接器是如何工作的,那么理解默认的连接器应该不会有任何问题。

本章从HTTP 1.1中的三个新功能开始。了解它们对于了解默认连接器的内部工作至关重要。之后,它引入了 org.apache.catalina.Connector ,这是所有连接器都必须实现的接口。然后,你将找到第3章中遇到的类,例如HttpConnector,HttpProcessor等。但是,这一次,它们比第3章中的类似类更高级。

HTTP 1.1 New Features(HTTP 1.1新功能)

本节说明HTTP 1.1的三个新功能。了解它们对于了解默认连接器如何处理HTTP请求至关重要。

Persistent Connections(持久连接)

在HTTP 1.1之前,每当浏览器连接到Web服务器时,每当请求的资源被发送后,服务器就会立即关闭连接。但是,一个互联网页面可能包含其他资源,如图片文件、applet等。因此,当一个页面被请求时,浏览器也需要下载该页面所引用的资源。如果该页面和它所引用的所有资源都使用不同的连接进行下载,那么这个过程将非常缓慢。这就是HTTP 1.1引入持久化连接的原因。使用持久化连接,当一个页面被下载时,服务器不会直接关闭连接。相反,它会等待Web客户端请求该页面引用的所有资源。这样一来,页面和被引用的资源就可以使用同一连接进行下载。考虑到建立和拆解HTTP连接是一项昂贵的操作,这为Web服务器、客户端和网络节省了大量的工作和时间。

持久连接是HTTP 1.1的默认连接。同样,为了明确起见,浏览器可以发送带有值keep-alive的请求标头连接:

connection: keep-alive
复制代码

Chunked Encoding(分块编码)

建立持久化连接的后果是,服务器可以从多个资源发送字节流,而客户端可以使用同一连接发送多个请求。因此,发送方必须发送每个请求或响应的内容长度头,以便接收方知道如何解释这些字节。然而,经常出现的情况是,发送方并不知道自己要发送多少个字节。例如,一个servlet容器可以在前几个字节变得可用时就开始发送响应,而不是等到所有的字节都准备好后才开始发送。这意味着,必须有一种方法来告诉收件人在无法提前知道content-length头的情况下如何解释字节流。

即使不需要发送多个请求或许多响应,服务器或客户端也不一定知道自己会发送多少数据。在HTTP 1.0中,服务器可以直接省去content-length头,然后继续向连接写入。当它完成后,它就会直接关闭连接。在这种情况下,客户端会继续读取,直到得到-1作为文件结束的指示。

HTTP 1.1使用称为传输编码的特殊标头来指示字节流将以块的形式发送。对于每个块,在数据之前先发送其长度(以十六进制表示),后跟CR/LF。事务用零长度的块标记。假设你要分两个块发送以下38个字节,第一个块的长度为29,第二个块的长度为9。

I'm as helpless as a kitten up a tree.
复制代码

你将发送以下信息:

1D/r/n
I'm as helpless as a kitten u
9/r/n
p a tree.
0/r/n
复制代码

1D(十六进制的29)表示第一个块由29个字节组成。0/r/n表示交易结束。

Use of the 100 (Continue) Status(使用100(继续)状态)

HTTP 1.1客户端可能会在发送请求体之前向服务器发送Expect: 100-continue头,然后等待服务器的确认。这种情况通常发生在客户机要发送一个长的请求体,但不确定服务器是否愿意接受。如果客户发送了长长的请求体后才发现服务器拒绝了,那就太浪费了。

收到Expect:100-continue头后,如果服务器愿意或可以处理请求,则服务器将使用以下100-continue头进行响应,后跟两对CRLF字符。

HTTP/1.1 100 Continue
复制代码

然后,服务器应继续读取输入流。

The Connector Interface(连接器接口)

Tomcat连接器必须实现 org.apache.catalina.Connector 接口。在此接口中的许多方法中,最重要的是 getContainersetContainercreateRequestcreateResponse

setContainer 用于将连接器与容器关联。 getContainer 返回关联的容器。 createRequest 为传入的HTTP请求构造一个请求对象,而 createResponse 创建一个响应对象。

org.apache.catalina.connector.http.HttpConnector 类是Connector接口的实现,将在下一部分“ HttpConnector类”中进行讨论。现在,仔细查看图4.1,了解默认连接器的UML类图。注意,为了简化该图,省略了Request和Response接口的实现。除了SimpleContainer类之外,类型名称中还省略了 org.apache.catalina 前缀。

因此,Connector应该读为 org.apache.catalina.Connector ,util.StringManager应该读为 org.apache.catalina.util.StringManager 等。

连接器与容器具有一对一关系。代表这种关系的箭头的可导航性表明,Connector知道Container,而不是相反。另外需要注意的是,与第3章不同的是,HttpConnector和HttpProcessor之间的关系是一对多的关系。

原文  https://juejin.im/post/5ec00aaa6fb9a043410a1e69
正文到此结束
Loading...