文档章节

Tomcat源码分析(二)--连接处理

epiclight
 epiclight
发布于 2015/10/09 14:48
字数 1306
阅读 99
收藏 13

目标:在这篇文章希望搞明白http请求到tomcat后是怎么由连接器转交到容器的?

      在上一节里已经启动了一个HttpConnector线程,并且也启动了固定数量的HttpProcessor线程。HttpConnector用来等待http连接,得到http连接后交给其中的一个HttpProcessor线程来处理。接下里具体看一下HttpConnector是怎么得到连接得,以及HttpProcessor是怎么处理的。当启动了HttpConnector线程后(在上一节已经知道怎么启动了),便在它的run方法里面循环等待:

[java] view plaincopyprint?

  1. public void run() {  

  2.     // Loop until we receive a shutdown command  

  3.     while (!stopped) {  

  4.         // Accept the next incoming connection from the server socket  

  5.         Socket socket = null;  

  6.         try {  

  7.             socket = serverSocket.accept();  

  8.             if (connectionTimeout > 0)  

  9.                 socket.setSoTimeout(connectionTimeout);  

  10.             socket.setTcpNoDelay(tcpNoDelay);  

  11.         } catch (AccessControlException ace) {  

  12.             log("socket accept security exception", ace);  

  13.             continue;  

  14.         } catch (IOException e) {  

  15.             try {  

  16.                 // If reopening fails, exit  

  17.                 synchronized (threadSync) {  

  18.                     if (started && !stopped)  

  19.                         log("accept error: ", e);  

  20.                     if (!stopped) {  

  21.                         serverSocket.close();  

  22.                         serverSocket = open();  

  23.                     }  

  24.                 }  

  25.                   

  26.             } catch (IOException ioe) {  

  27.                 log("socket reopen, io problem: ", ioe);  

  28.                 break;  

  29.             } catch (KeyStoreException kse) {  

  30.                 log("socket reopen, keystore problem: ", kse);  

  31.                 break;  

  32.             } catch (NoSuchAlgorithmException nsae) {  

  33.                 log("socket reopen, keystore algorithm problem: ", nsae);  

  34.                 break;  

  35.             } catch (CertificateException ce) {  

  36.                 log("socket reopen, certificate problem: ", ce);  

  37.                 break;  

  38.             } catch (UnrecoverableKeyException uke) {  

  39.                 log("socket reopen, unrecoverable key: ", uke);  

  40.                 break;  

  41.             } catch (KeyManagementException kme) {  

  42.                 log("socket reopen, key management problem: ", kme);  

  43.                 break;  

  44.             }  

  45.   

  46.             continue;  

  47.         }  

  48.   

  49.         // Hand this socket off to an appropriate processor  

  50.         HttpProcessor processor = createProcessor();  

  51.         if (processor == null) {  

  52.             try {  

  53.                 log(sm.getString("httpConnector.noProcessor"));  

  54.                 socket.close();  

  55.             } catch (IOException e) {  

  56.                 ;  

  57.             }  

  58.             continue;  

  59.         }  

  60.        

  61.         processor.assign(socket);  

  62.   

  63.     }  

  64.   

  65.     // Notify the threadStop() method that we have shut ourselves down  

  66.    

  67.     synchronized (threadSync) {  

  68.         threadSync.notifyAll();  

  69.     }  

  70.   

  71. }  

这里很关键的就是socket = serverSocket.accept();和processor.assign(socket); 在循环里面内,serverSocket.accept();负责接收http请求然后赋值给socket,最后交给其中一个processor处理。这里processor并不是等到需要的时候再实例化,而是在HttpConnector初始化的时候已经有了若干个processor,在httpConnector里有这样一个声明:

[java] view plaincopyprint?

  1. private Stack processors = new Stack();  

表明httpConnector里面持有一个包含HttpProcessor对象的栈,需要的时候拿出来就是了。看一下createProcessor函数就能比较明白了:

[java] view plaincopyprint?

  1. private HttpProcessor createProcessor() {  

  2.      synchronized (processors) {  

  3.          if (processors.size() > 0) {  

  4.              return ((HttpProcessor) processors.pop()); //从processors栈中弹出一个processor  

  5.          }  

  6.          if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {  

  7.              return (newProcessor());  

  8.          } else {  

  9.              if (maxProcessors < 0) {  

  10.                  return (newProcessor());  

  11.              } else {  

  12.                  return (null);  

  13.              }  

  14.          }  

  15.      }  

  16.   

  17.  }  


接下来由processor.assign(socket); 记住这个方法是异步的,不需要等待HttpProcessor来处理完成,所以HttpConnector才能不间断的传入Http请求,在HttpProcessor里有两个方法比较重要,这两个方法协调处理了由HttpConnector传来的socket:

[java] view plaincopyprint?

  1.  synchronized void assign(Socket socket) {  

  2.   

  3.     // Wait for the Processor to get the previous Socket  

  4.     while (available) {  

  5.         try {  

  6.             wait();  

  7.         } catch (InterruptedException e) {  

  8.         }  

  9.     }  

  10.   

  11.     // Store the newly available Socket and notify our thread  

  12.     this.socket = socket;  

  13.     available = true;  

  14.     notifyAll();  

  15.   

  16.     if ((debug >= 1) && (socket != null))  

  17.         log(" An incoming request is being assigned");  

  18.   

  19. }  

  20.   

  21.   

  22. private synchronized Socket await() {  

  23.   

  24.     // Wait for the Connector to provide a new Socket  

  25.     while (!available) {  

  26.         try {  

  27.             wait();  

  28.         } catch (InterruptedException e) {  

  29.         }  

  30.     }  

  31.   

  32.     // Notify the Connector that we have received this Socket  

  33.     Socket socket = this.socket;  

  34.     available = false;  

  35.     notifyAll();  

  36.   

  37.     if ((debug >= 1) && (socket != null))  

  38.         log("  The incoming request has been awaited");  

  39.   

  40.     return (socket);  

  41.   

  42. }  

看一下HttpProcessor的run方法:

[java] view plaincopyprint?

  1. public void run() {  

  2.   

  3.        // Process requests until we receive a shutdown signal  

  4.        while (!stopped) {  

  5.   

  6.            // Wait for the next socket to be assigned  

  7.            Socket socket = await();  

  8.            if (socket == null)  

  9.                continue;  

  10.   

  11.            // Process the request from this socket  

  12.            try {  

  13.                process(socket);  

  14.            } catch (Throwable t) {  

  15.                log("process.invoke", t);  

  16.            }  

  17.   

  18.            // Finish up this request  

  19.            connector.recycle(this);  

  20.   

  21.        }  

  22.   

  23.        // Tell threadStop() we have shut ourselves down successfully  

  24.        synchronized (threadSync) {  

  25.            threadSync.notifyAll();  

  26.        }  

  27.   

  28.    }  


很明显,在它的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方法主要的代码如下:

[java] view plaincopyprint?

  1. private void process(Socket socket) {  

  2.                    input = new SocketInputStream(socket.getInputStream(),  

  3.                                           connector.getBufferSize());  

  4.                    //解析一下连接的地址,端口什么的  

  5.                     parseConnection(socket);  

  6.                     //解析请求头的第一行,即:方法,协议,uri  

  7.                     parseRequest(input, output);  

  8.                     if (!request.getRequest().getProtocol()  

  9.                         .startsWith("HTTP/0"))  

  10.                     parseHeaders(input);//解析http协议的头部  

  11.                     ..............................................  

  12.                     connector.getContainer().invoke(request, response);  

  13.                     .............................................  

  14. }  

在那些parse××方法里面会对request,response对象进行初始化,然后调用容器的invoke方法进行处理,至此,http请求过来的连接已经完美的转交给容器处理,容器剩下的问题就是要最终转交给哪个servlet或者jsp的问题。前面我们知道,一个连接会跟一个容器相连,一个级别大的容器会有一个或者多个子容器,最小的容器是Wrapper,对应一个servlet,在这里我们只要知道请求的路径决定了最终会选择哪个wrapper,wrapper最终会调用servlet的。至少一开始提出来的问题已经明白了。这里又有一个问题,在调用invoke方法是有这样的connector.getContainer的代码,即通过连接器得到跟它关联的容器,这个连接器是什么时候跟容器关联上的?详见下篇:Tomcat源码分析(三)--连接器是如何与容器关联的?


本文转载自:http://blog.csdn.net/haitao111313/article/details/7718774

epiclight
粉丝 3
博文 41
码字总数 79
作品 0
深圳
架构师
私信 提问
Tomcat7.0源码分析——请求原理分析(中)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/51828607 前言   在《Tomcat7.0源码分析——请求原理分析(上)》一文中已经介绍...

泰山不老生
2016/07/07
0
0
从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一)

从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一) 收藏 如何正确使用NIO来构架网络服务器一直是最近思考的一个问题,于是乎分析了一下Jetty、Tomcat和Mina有关NIO的源码,发现...

光石头
2011/02/20
0
0
Tomcat7.0源码分析——请求原理分析(上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/51645799 前言   谈起Tomcat的诞生,最早可以追溯到1995年。近20年来,Tomcat始终...

泰山不老生
2016/06/30
0
0
Tomcat源码分析(二)请求过程分析

经过前面几篇文章的分析,我们对Tomcat的框架有了一定得掌握,对于各个模块的功能也有了大致了解,这篇文章主要分析Connector如何将请求分发到Engine,以及最后到Servlet处理。 从Tomcat类结...

AaronSheng
2016/11/29
34
0
异步Servlet编程 | Servlet3.0新特性

前天在扒Tomcat源码的时候在装配Servlet的时候我们除了看见了比较熟悉的loadOnStartup参数之外,另外一个不太熟悉的参数asyncSupported就是我们今天要讨论的主题,我们的关注点随即也从Servl...

Float_Luuu
2016/01/03
1K
2

没有更多内容

加载失败,请刷新页面

加载更多

零基础学画画应该从哪开始?

零基础学画画应该从哪开始?一种是从小有兴趣,喜欢涂鸦,喜欢将自己的创意和想法表现出来;另一种是长大后审美提高,开始对绘画艺术感兴趣,从而开始从零基础学起。 推荐大家可以搜一下:轻微...

设绘嗨
18分钟前
2
0
你编写的程序高效、优雅吗?阿里架构师教你编写高效优雅Java程序

面向对象 构造器参数太多怎么办? 用 builder 模式,用在 1、5 个或者 5 个以上的成员变量 2、参数不多,但是在未来,参数会增加 Builder 模式: 属于对象的创建模式,一般有 1. 抽象建造者:...

kx33389
22分钟前
2
0
PDF 文档操作Java类库Spire.PDF for Java v2.7.6发布上线!| 附下载

Spire.PDF for Java是一款专门对 PDF 文档进行操作的 Java 类库。该类库的主要功能在于帮助开发人员在 Java 应用程序(J2SE和J2EE)中生成 PDF 文档和操作现有 PDF 文档,并且运行环境无需安...

mnrssj
31分钟前
1
0
初探云原生应用管理(二): 为什么你必须尽快转向 Helm v3

在研究了一番“开放云原生应用中心(AppHub)”之后,程序员小张似乎已经明白了“云原生应用”到底是怎么一回事情。 “不就是 Helm 嘛!” 这不,小张这就准备把自己开发多年的“图书馆管理系...

zhaowei121
34分钟前
0
0
「工具」三分钟了解一款思维导图工具:XMind Zen

一款非常实用的商业思维导图软件,融合艺术与创造力。致力于高效的可视化思维,强调软件的跨平台使用,帮助用户提高生产效率。 相关信息 · 操作系统:macOS / Windows / Linux · 官方网站:...

极光推送
35分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部