目标:在这篇文章希望搞明白http请求到tomcat后是怎么由连接器转交到容器的?
在上一节里已经启动了一个HttpConnector线程,并且也启动了固定数量的HttpProcessor线程。HttpConnector用来等待http连接,得到http连接后交给其中的一个HttpProcessor线程来处理。接下里具体看一下HttpConnector是怎么得到连接得,以及HttpProcessor是怎么处理的。当启动了HttpConnector线程后(在上一节已经知道怎么启动了),便在它的run方法里面循环等待:
- public void run() {
- // Loop until we receive a shutdown command
- while (!stopped) {
- // Accept the next incoming connection from the server socket
- Socket socket = null ;
- try {
- socket = serverSocket.accept();
- if (connectionTimeout > 0 )
- socket.setSoTimeout(connectionTimeout);
- socket.setTcpNoDelay(tcpNoDelay);
- } catch (AccessControlException ace) {
- log( "socket accept security exception" , ace);
- continue ;
- } catch (IOException e) {
- try {
- // If reopening fails, exit
- synchronized (threadSync) {
- if (started && !stopped)
- log( "accept error: " , e);
- if (!stopped) {
- serverSocket.close();
- serverSocket = open();
- }
- }
- } catch (IOException ioe) {
- log( "socket reopen, io problem: " , ioe);
- break ;
- } catch (KeyStoreException kse) {
- log( "socket reopen, keystore problem: " , kse);
- break ;
- } catch (NoSuchAlgorithmException nsae) {
- log( "socket reopen, keystore algorithm problem: " , nsae);
- break ;
- } catch (CertificateException ce) {
- log( "socket reopen, certificate problem: " , ce);
- break ;
- } catch (UnrecoverableKeyException uke) {
- log( "socket reopen, unrecoverable key: " , uke);
- break ;
- } catch (KeyManagementException kme) {
- log( "socket reopen, key management problem: " , kme);
- break ;
- }
- continue ;
- }
- // Hand this socket off to an appropriate processor
- HttpProcessor processor = createProcessor();
- if (processor == null ) {
- try {
- log(sm.getString( "httpConnector.noProcessor" ));
- socket.close();
- } catch (IOException e) {
- ;
- }
- continue ;
- }
- processor.assign(socket);
- }
- // Notify the threadStop() method that we have shut ourselves down
- synchronized (threadSync) {
- threadSync.notifyAll();
- }
- }
- private Stack processors = new Stack();
- private HttpProcessor createProcessor() {
- synchronized (processors) {
- if (processors.size() > 0 ) {
- return ((HttpProcessor) processors.pop()); //从processors栈中弹出一个processor
- }
- if ((maxProcessors > 0 ) && (curProcessors < maxProcessors)) {
- return (newProcessor());
- } else {
- if (maxProcessors < 0 ) {
- return (newProcessor());
- } else {
- return ( null );
- }
- }
- }
- }
接下来由processor.assign(socket); 记住这个方法是异步的,不需要等待HttpProcessor来处理完成,所以HttpConnector才能不间断的传入Http请求,在HttpProcessor里有两个方法比较重要,这两个方法协调处理了由HttpConnector传来的socket:
- synchronized void assign(Socket socket) {
- // Wait for the Processor to get the previous Socket
- while (available) {
- try {
- wait();
- } catch (InterruptedException e) {
- }
- }
- // Store the newly available Socket and notify our thread
- this .socket = socket;
- available = true ;
- notifyAll();
- if ((debug >= 1 ) && (socket != null ))
- log( " An incoming request is being assigned" );
- }
- private synchronized Socket await() {
- // Wait for the Connector to provide a new Socket
- while (!available) {
- try {
- wait();
- } catch (InterruptedException e) {
- }
- }
- // Notify the Connector that we have received this Socket
- Socket socket = this .socket;
- available = false ;
- notifyAll();
- if ((debug >= 1 ) && (socket != null ))
- log( " The incoming request has been awaited" );
- return (socket);
- }
看一下HttpProcessor的run方法:
- public void run() {
- // Process requests until we receive a shutdown signal
- while (!stopped) {
- // Wait for the next socket to be assigned
- Socket socket = await();
- if (socket == null )
- continue ;
- // Process the request from this socket
- try {
- process(socket);
- } catch (Throwable t) {
- log( "process.invoke" , t);
- }
- // Finish up this request
- connector.recycle( this );
- }
- // Tell threadStop() we have shut ourselves down successfully
- synchronized (threadSync) {
- threadSync.notifyAll();
- }
- }
很明显,在它的run方法一开始便是调用上面的await方法来等待(因为一开始available变量为false),所以HttpProcessor会一直阻塞,直到有线程来唤醒它。当从HttpConnector中调用processor.assign(socket),会把socket传给此HttpProcessor对象,并设置available为true,调用notifyAll()唤醒该processor线程以处理socket。同时,在await方法中又把available设置成false,因此又回到初始状态,即可以重新接受socket。
这里处理socket的方法是process(socket),主要作用有两点,1:解析这个socket,即解析http请求,包括请求方法,请求协议等,以填充request,response对象(是不是很熟悉,在servlet和jsp开发经常用到的request,response对象就是从这里来的)。2:传入request,response对象给和HttpConnector绑定的容器,让容器来调用invoke方法进行处理。process方法主要的代码如下:
- private void process(Socket socket) {
- input = new SocketInputStream(socket.getInputStream(),
- connector.getBufferSize());
- //解析一下连接的地址,端口什么的
- parseConnection(socket);
- //解析请求头的第一行,即:方法,协议,uri
- parseRequest(input, output);
- if (!request.getRequest().getProtocol()
- .startsWith( "HTTP/0" ))
- parseHeaders(input); //解析http协议的头部
- ..............................................
- connector.getContainer().invoke(request, response);
- .............................................
- }
更多文章、技术交流、商务合作、联系博主
微信扫码或搜索:z360901061
微信扫一扫加我为好友
QQ号联系: 360901061
您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。
【本文对您有帮助就好】元