当前位置: 首页 > news >正文

添加qq好友的超链接做网站外行学习个人网站建设

添加qq好友的超链接做网站,外行学习个人网站建设,网站建设论文摘要,wordpress wp list pages【0】README0.0#xff09;本文部分文字描述转自#xff1a;“深入剖析tomcat”#xff0c;旨在学习 tomat(4)Tomat的默认连接器 的基础知识#xff1b;0.1#xff09;Tomcat中的连接器是一个独立的模块#xff0c;可以插入到servlet容器中#xff0c;而且还有很多连接器…【0】README0.0本文部分文字描述转自“深入剖析tomcat”旨在学习 tomat(4)Tomat的默认连接器 的基础知识0.1Tomcat中的连接器是一个独立的模块可以插入到servlet容器中而且还有很多连接器可以使用0.2Tomcat中使用的连接器必须满足如下要求requirementr1实现 org.apache.catalina.Connector 接口 r2负责创建实现了 org.apache.catalina.Request接口的request对象 r3负责创建实现了 org.apache.catalina.Response接口的response对象 0.3连接器会等待HTTP请求以创建request 和 response对象然后调用 org.apache.catalina.Container接口的 invoke方法将request对象和response对象传给 servlet容器。invoke() 方法签名如下干货——这里涉及到类加载器public void invoke(Request request, Response response) // SimpleContainer.invokethrows IOException, ServletException {String servletName ( (HttpServletRequest) request).getRequestURI();servletName servletName.substring(servletName.lastIndexOf(/) 1);URLClassLoader loader null;try { // 创建类加载器URL[] urls new URL[1];URLStreamHandler streamHandler null;File classPath new File(WEB_ROOT);String repository (new URL(file, null, classPath.getCanonicalPath() File.separator)).toString() ;urls[0] new URL(null, repository, streamHandler);loader new URLClassLoader(urls);}catch (IOException e) {System.out.println(e.toString() );}Class myClass null;try {myClass loader.loadClass(servlet. servletName);}catch (ClassNotFoundException e) {System.out.println(e.toString());}Servlet servlet null;try {servlet (Servlet) myClass.newInstance(); // 创建请求URI对应的servlet实例 servlet.service((HttpServletRequest) request, (HttpServletResponse) response);}......}0.3.1invoke方法内部servlet容器会载入相应的servlet类调用其 service() 方法管理session对象记录错误消息等操作 0.3.2Tomcat4的默认连接器使用了一些优化方法一、使用了一个对象池来避免了频繁创建对象带来的性能损耗二、在很多地方Tomcat4 的默认连接器使用了字符数组来代替字符串干货——Tomcat4的默认连接器使用了一些优化方法 0.4for complete source code, please visit https://github.com/pacosonTang/HowTomcatWorks/tree/master/chapter40.5本文讲解的是 tomcat中的默认连接器而 这篇博文 tomcat(3)连接器 讲解的是以前的前辈自定义的连接器功能和tomcat默认连接器类似这旨在学习 tomcat中默认连机器的原理。0.6温馨建议建议阅读本文之前已阅读过 tomcat(1~3)的系列文章因为它们是环环相扣的 【1】HTTP 1.1 的新特性【1.1】持久连接1intro to persistent connect在HTTP1.1之前 无论浏览器何时连接到web server当server返回请求资源后会断开与浏览器的连接但网页上会包含一些其他资源如图片所以当请求一个页面时浏览器还需要下载这些被页面引用的资源。如果页面和它引用的所有资源文件都使用不同的连接进行下载的话处理过程会很慢这也就是为什么会引入持久连接干货——引入持久连接的原因1.1使用持久连接后当下载了页面后server并不会立即关闭连接相反它会等待web client请求被该页面引用的所有资源。这样一来页面和被引用的资源都会使用同一个连接来下载。考虑到建立/关闭 HTTP 连接是一个系统开销很大的操作使用同一个连接来下载所有的资源会为web server client 和 网络节省很多时间和工作量1.2如何默认使用持久连接浏览器发送如下的请求头信息 connection: keep-alive【1.2】块编码1建立持久连接后server 可以从多个资源发送字节流而客户端也可以使用该连接发送多个请求。这样的结果就是发送方必须在每个请求或响应中添加 content-length 头信息。这样接收方才知道如何解释这些字节信息。但发送方通常不知道要发送多少字节所以必须有一种方法来告诉接收方在不知道发送内容长度的case下如何解析已经接受到的内容2HTTP1.1 使用一个名为 transfer-encoding 的特殊请求头来指明字节流将会分块发送。对每一个块块的长度以16进制表示后面会有一个回车/换行符CR/LF然后是具体的数据一个事务以一个长度为0的块标记。2.1看个荔枝若要用两个块发送下面38个字节的内容其中一块为29个字节第2个块为9个字节干货——块编码的一个荔枝Im as helpless as a kitten up a tree. 那么实际上应该发送如下内容 1D\r\n Im as helpless as a kitten u 9\r\n p a tree. 0\r\n 1D 的10进制表示是29 表明第一个块的长度是29个字节\0\r\n 表明事务已经完成【1.3】状态码100的使用 1使用HTTP1.1的client 可以在向server发送请求体之前发送如下的请求头并等待server的确认Expect: 100-continue //客户端发送2server接收到 “Expect: 100-continue”请求头后若它可以接收并处理该请求时发送如下响应头HTTP/1.1 100 continue //注意返回内容后面要加上 CRLF 字符。然后server 继续读取输入流的内容。【2】Connector接口Tomcat的连接器必须实现的接口1该接口中声明了很多方法最重要的是 getContainer(), setContainer(), createRequest(), createResponse() 方法【3】HttpConnector类实现了Connector Runnable Lifecycle 接口public final class HttpConnectorimplements Connector, Lifecycle, Runnable {1Lifecycle接口用于维护每个实现了 该接口的每个Catalina组件的生命周期2HttpConnector实现了Lifecycle接口因此当创建一个 HttpConnector实例后就应该调用其initialize方法和start方法在组件的整个生命周期内这两个方法只应该被调用一次public final class Bootstrap {public static void main(String[] args) {HttpConnector connector new HttpConnector();SimpleContainer container new SimpleContainer();connector.setContainer(container);try {connector.initialize();connector.start();// make the application wait until we press any key.System.in.read();}catch (Exception e) {e.printStackTrace();}} }【3.1】创建服务器套接字1HttpConnector类的 initialize方法会调用一个私有方法open()后者返回一个java.net.ServerSocket实例赋值给成员变量serverSocket它是通过open方法从一个服务器套接字工厂得到这个实例public void initialize() // span stylefont-family: 宋体; font-size: 16px; line-height: 24px;strongHttpConnector.initialize()/strong/spanthrows LifecycleException {if (initialized)throw new LifecycleException (sm.getString(httpConnector.alreadyInitialized));this.initializedtrue;Exception eRethrow null;// Establish a server socket on the specified porttry {serverSocket open();} catch (IOException ioe) {log(httpConnector, io problem: , ioe);eRethrow ioe;} catch (KeyStoreException kse) {log(httpConnector, keystore problem: , kse);eRethrow kse;} catch (NoSuchAlgorithmException nsae) {log(httpConnector, keystore algorithm problem: , nsae);eRethrow nsae;} catch (CertificateException ce) {log(httpConnector, certificate problem: , ce);eRethrow ce;} catch (UnrecoverableKeyException uke) {log(httpConnector, unrecoverable key: , uke);eRethrow uke;} catch (KeyManagementException kme) {log(httpConnector, key management problem: , kme);eRethrow kme;}if ( eRethrow ! null )throw new LifecycleException(threadName .open, eRethrow);}private ServerSocket open() // HttpConnector.open()throws IOException, KeyStoreException, NoSuchAlgorithmException,CertificateException, UnrecoverableKeyException,KeyManagementException{// Acquire the server socket factory for this ConnectorServerSocketFactory factory getFactory();// If no address is specified, open a connection on all addressesif (address null) {log(sm.getString(httpConnector.allAddresses));try {return (factory.createSocket(port, acceptCount));} catch (BindException be) {throw new BindException(be.getMessage() : port);}}// Open a server socket on the specified addresstry {InetAddress is InetAddress.getByName(address);log(sm.getString(httpConnector.anAddress, address));try {return (factory.createSocket(port, acceptCount, is));} catch (BindException be) {throw new BindException(be.getMessage() : address : port);}} catch (Exception e) {log(sm.getString(httpConnector.noAddress, address));try {return (factory.createSocket(port, acceptCount));} catch (BindException be) {throw new BindException(be.getMessage() : port);}}}【3.2】维护 HttpProcessor 实例1在Tomcat默认的连接器中HttpProcessor实例有一个HttpProcessor 对象池每个HttpProcessor 实例都运行在其自己的线程中。这样HttpConnector实例就可以同时处理多个 HTTP请求了干货——HttpProcessor 对象池就是一个Stack并不是Vectorprivate Stack processors new Stack(); // HttpConnector.java void recycle(HttpProcessor processor) { // HttpConnector.java// if (debug 2)// log(recycle: Recycling processor processor);processors.push(processor);}private HttpProcessor createProcessor() {synchronized (processors) {if (processors.size() 0) {// if (debug 2)// log(createProcessor: Reusing existing processor);return ((HttpProcessor) processors.pop()); // attend for this line.}if ((maxProcessors 0) (curProcessors maxProcessors)) {// if (debug 2)// log(createProcessor: Creating new processor);return (newProcessor());} else {if (maxProcessors 0) {// if (debug 2)// log(createProcessor: Creating new processor);return (newProcessor());} else {// if (debug 2)// log(createProcessor: Cannot create new processor);return (null);}}}}补充 Collection体系 |--List元素是有序的元素可以重复因为该集合体系有索引     |--ArrayList底层的数据结构使用的是数组结构特点查询速度很快但是增删稍慢线程不同步     |--LinkedList底层使用的是链表数据结构特点增删速度很快查询稍慢     |--Vector底层是数组数据结构线程同步被ArrayList替代了 |--Set  元素是无序的元素不可以重复 为什么要用 ArrayList 取代 Vector呢 因为 Vector 类的所有方法都是同步的可以由两个线程安全的访问一个 Vector对象但是 如果由一个线程访问 Vector 代码需要在同步操作上 耗费大量的时间干货——ArrayList非同步访问而Vector同步访问而ArryaList 不是同步 的 所以 建议在不需要同步时 使用 ArrayList 而不要使用 Vector 补充over 2在HttpConnector中创建的HttpProcessor 实例的个数由两个变量决定minProcessors 和 maxProcessors2.1初始HttpConnector对象会依据minProcessors的数值来创建 HttpProcessor实例若是请求的数目超过了HttpProcessor 实例所能处理的范围HttpConnector 实例就会创建更多的HttpProcessor实例直到数目达到  maxProcessors 限定的范围2.2若希望可以持续地创建 HttpProcessor实例 就可以将 maxProcessors 设定为负值2.3看个代码下面的代码是在 HttpConnector 类中的start方法中创建初始数量的 HTTPProcessor实例的部分实现干货——HttpConnector.start方法调用了HttpConnector.newProcessor方法而HttpConnector.newProcessor方法调用了HttpProcessor.start方法public void start() throws LifecycleException { // HttpConnector.start()// Validate and update our current stateif (started)throw new LifecycleException(sm.getString(httpConnector.alreadyStarted));threadName HttpConnector[ port ];lifecycle.fireLifecycleEvent(START_EVENT, null);started true;// Start our background threadthreadStart(); // invoke run method.// Create the specified minimum number of processorswhile (curProcessors minProcessors) {if ((maxProcessors 0) (curProcessors maxProcessors))break;HttpProcessor processor newProcessor();recycle(processor);}}private HttpProcessor newProcessor() { // Hspan stylefont-family: 宋体;ttpConnector.newProcessor()/span// if (debug 2)// log(newProcessor: Creating new processor);HttpProcessor processor new HttpProcessor(this, curProcessors);if (processor instanceof Lifecycle) {try {((Lifecycle) processor).start();} catch (LifecycleException e) {log(newProcessor, e);return (null);}}created.addElement(processor); // created is a Vector Collection.return (processor);} private Vector created new Vector();void recycle(HttpProcessor processor) { // HttpContainer.recycle()// if (debug 2)// log(recycle: Recycling processor processor);processors.push(processor);}public void stop() throws LifecycleException {// Validate and update our current stateif (!started)throw new LifecycleException(sm.getString(httpConnector.notStarted));lifecycle.fireLifecycleEvent(STOP_EVENT, null);started false;// Gracefully shut down all processors we have createdfor (int i created.size() - 1; i 0; i--) {HttpProcessor processor (HttpProcessor) created.elementAt(i); // this line.if (processor instanceof Lifecycle) {try {((Lifecycle) processor).stop();} catch (LifecycleException e) {log(HttpConnector.stop, e);}}}synchronized (threadSync) {// Close the server socket we were usingif (serverSocket ! null) {try {serverSocket.close();} catch (IOException e) {;}}// Stop our background threadthreadStop();}serverSocket null;}AttentionA0显然变量created是private类型其在HttpConnector.java 中出现了3次一次是 private Vector created new Vector(); 一次是created.addElement(processor);还有一次是stop方法中上述最后一段代码干货——但HttpProcessor的对象池不是Vector而是Stack A1其中newProcessor方法负责创建 HttpProcessor 实例并将 curProcessors 加1recycle() 方法将创建的HttpProcessor 对象入栈 A2每个 HttpProcessor 实例负责解析HTTP请求行和请求头 填充 request对象 void recycle(HttpProcessor processor) { // // if (debug 2)// log(recycle: Recycling processor processor);processors.push(processor); // span stylefont-weight: bold; font-family: 宋体;processors is a stack./span} private Stack processors new Stack(); // HttpConnector.java 【3.3】提供HTTP请求服务1HttpConnector类的主要业务逻辑在其run() 方法中。run() 方法包含一个 while循环在该循环体内服务器套接字等待 HTTP请求直到HttpConnector对象关闭public void run() { // HttpConnector.run()// Loop until we receive a shutdown commandwhile (!stopped) {// Accept the next incoming connection from the server socketSocket socket null;try {// if (debug 3)// log(run: Waiting on serverSocket.accept());socket serverSocket.accept();// if (debug 3)// log(run: Returned from serverSocket.accept());if (connectionTimeout 0)socket.setSoTimeout(connectionTimeout);socket.setTcpNoDelay(tcpNoDelay);} catch (AccessControlException ace) {log(socket accept security exception, ace);continue;} catch (IOException e) {// if (debug 3)// log(run: Accept returned IOException, e);try {// If reopening fails, exitsynchronized (threadSync) {if (started !stopped)log(accept error: , e);if (!stopped) {// if (debug 3)// log(run: Closing server socket);serverSocket.close();// if (debug 3)// log(run: Reopening server socket);serverSocket open();}}// if (debug 3)// log(run: IOException processing completed);} 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 processorHttpProcessor processor createProcessor();if (processor null) {try {log(sm.getString(httpConnector.noProcessor));socket.close();} catch (IOException e) {;}continue;}// if (debug 3)// log(run: Assigning socket to processor processor);processor.assign(socket);// The processor will recycle itself when it finishes}// Notify the threadStop() method that we have shut ourselves down// if (debug 3)// log(run: Notifying threadStop() that we have shut down);synchronized (threadSync) {threadSync.notifyAll();}}2对于每个引入的HTTP请求它通过 调用其私有方法 createProcessor() 获得一个HttpProcessor对象HttpProcessor processor createProcessor(); // invoked by HttpContainer.run() method. private Stack processors new Stack(); // you should know the processors is a Stack.private HttpProcessor createProcessor() { // HttpConnector.createProcessor() synchronized (processors) {if (processors.size() 0) {// if (debug 2)// log(createProcessor: Reusing existing processor);return ((HttpProcessor) processors.pop());}if ((maxProcessors 0) (curProcessors maxProcessors)) {// if (debug 2)// log(createProcessor: Creating new processor);return (newProcessor());} else {if (maxProcessors 0) {// if (debug 2)// log(createProcessor: Creating new processor);return (newProcessor());} else {// if (debug 2)// log(createProcessor: Cannot create new processor);return (null);}}}}span stylefont-family: 宋体; /span3若createProcessor() 方法的返回值不是null则会将客户端套接字传入到 HttpProcessor类的 assign()方法中// Hand this socket off to an appropriate processorHttpProcessor processor createProcessor(); // these code are located in HttpConnector.run() if (processor null) {try {log(sm.getString(httpConnector.noProcessor));socket.close();} catch (IOException e) {;}continue;}// if (debug 3)// log(run: Assigning socket to processor processor);processor.assign(socket); // this line, invoked by HttpConnector.run method.// The processor will recycle itself when it finishes}// Notify the threadStop() method that we have shut ourselves down// if (debug 3)// log(run: Notifying threadStop() that we have shut down);synchronized (threadSync) {threadSync.notifyAll();}synchronized void assign(Socket socket) {// Wait for the Processor to get the previous Socketwhile (available) {try {wait();} catch (InterruptedException e) {}}// Store the newly available Socket and notify our threadthis.socket socket;available true;notifyAll();if ((debug 1) (socket ! null))log( An incoming request is being assigned);}4现在HttpProcessor实例的任务是读取套接字的输入流解析HTTP请求。这里需要注意的是assign方法直接返回而不需要等待 HttpProcessor 实例完成解析这样 HttpContainer才能持续服务传入的 HTTP请求而 HttpProcessor 实例是在其自己的线程中完成解析工作的【4】HttpProcessor类主要讲解该类的assign方法的异步实现0HttpProcessor类中另一个重要的方法是其私有方法process() 方法该方法负责解析 HTTP请求并调用相应的servlet容器的invoke方法private void process(Socket socket) {boolean ok true;boolean finishResponse true;SocketInputStream input null;OutputStream output null;// Construct and initialize the objects we will needtry {input new SocketInputStream(socket.getInputStream(),connector.getBufferSize());} catch (Exception e) {log(process.create, e);ok false;}keepAlive true;while (!stopped ok keepAlive) {finishResponse true;try {request.setStream(input);request.setResponse(response);output socket.getOutputStream();response.setStream(output);response.setRequest(request);((HttpServletResponse) response.getResponse()).setHeader(Server, SERVER_INFO);} catch (Exception e) {log(process.create, e);ok false;}// Parse the incoming requesttry {if (ok) {parseConnection(socket);parseRequest(input, output);if (!request.getRequest().getProtocol().startsWith(HTTP/0))parseHeaders(input);if (http11) {// Sending a request acknowledge back to the client if// requested.ackRequest(output);// If the protocol is HTTP/1.1, chunking is allowed.if (connector.isChunkingAllowed())response.setAllowChunking(true);}}} catch (EOFException e) {// Its very likely to be a socket disconnect on either the // client or the serverok false;finishResponse false;} catch (ServletException e) {ok false;try {((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_BAD_REQUEST);} catch (Exception f) {;}} catch (InterruptedIOException e) {if (debug 1) {try {log(process.parse, e);((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_BAD_REQUEST);} catch (Exception f) {;}}ok false;} catch (Exception e) {try {log(process.parse, e);((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_BAD_REQUEST);} catch (Exception f) {;}ok false;}// Ask our Container to process this requesttry {((HttpServletResponse) response).setHeader(Date, FastHttpDateFormat.getCurrentDate());if (ok) {connector.getContainer().invoke(request, response); // process method invokes the invoke method of corresponding servlet container}} catch (ServletException e) {log(process.invoke, e);try {((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);} catch (Exception f) {;}ok false;} catch (InterruptedIOException e) {ok false;} catch (Throwable e) {log(process.invoke, e);try {((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);} catch (Exception f) {;}ok false;}// Finish up the handling of the requestif (finishResponse) {try {response.finishResponse();} catch (IOException e) {ok false;} catch (Throwable e) {log(process.invoke, e);ok false;}try {request.finishRequest();} catch (IOException e) {ok false;} catch (Throwable e) {log(process.invoke, e);ok false;}try {if (output ! null)output.flush();} catch (IOException e) {ok false;}}// We have to check if the connection closure has been requested// by the application or the response stream (in case of HTTP/1.0// and keep-alive).if ( close.equals(response.getHeader(Connection)) ) {keepAlive false;}// End of request processingstatus Constants.PROCESSOR_IDLE;// Recycling the request and the response objectsrequest.recycle();response.recycle();}try {shutdownInput(input);socket.close();} catch (IOException e) {;} catch (Throwable e) {log(process.invoke, e);}socket null;}1在Tomcat的默认连接器中HttpProcessor类实现了 java.lang.Runnable 接这样每个HttpProcessor实例就可以运行在自己的线程中了称为“处理器线程”。为每个 HttpProcessor 对象创建 HttpProcessor 实例后会调用其start方法启动HttpProcessor 实例的处理器线程下面是 HttpProcessor类中的run方法的实现干货——注意区分开HttpProcessor.run方法和 HttpConnector.run方法 public void run() { // HttpProcessor.run()// Process requests until we receive a shutdown signalwhile (!stopped) {// Wait for the next socket to be assignedSocket socket await(); // this line, span stylefont-family: 宋体; font-size: 16px; line-height: 24px;run方法的while循环执行到 await方法时会阻塞/spanif (socket null)continue;// Process the request from this sockettry {process(socket);} catch (Throwable t) {log(process.invoke, t);}// Finish up this requestconnector.recycle(this);}// Tell threadStop() we have shut ourselves down successfullysynchronized (threadSync) {threadSync.notifyAll();}}private synchronized Socket await() { // HttpProcessor.await()// Wait for the Connector to provide a new Socketwhile (!available) {try {wait();} catch (InterruptedException e) {}}// Notify the Connector that we have received this SocketSocket socket this.socket;available false;notifyAll();if ((debug 1) (socket ! null))log( The incoming request has been awaited);return (socket);}对以上代码的分析AnalysisA1run方法中的while循环做如下几件事情获取套接字对象进行处理调用连接器的recycle() 方法将当前的 HttpRequest实例压回栈中。 A2下面是 HttpConnector类中 recycle方法的代码  */void recycle(HttpProcessor processor) {// if (debug 2)// log(recycle: Recycling processor processor);processors.push(processor);} A3run方法的while循环执行到 await方法时会阻塞。await方法会阻塞处理器线程的控制流直到它从HttpConnector中获得了新的Socket对象。即直到HttpConnector对象调用 HttpProcessor实例的assign方法前都会一直阻塞 但是await方法 和assign方法并不是运行在同一个线程中的。assign方法是从 HttpConnector对象的 run方法中调用的。我们称 HttpConnector实例中run方法运行时所在的线程为“连接器线程”。通过使用available的布尔变量和 Object.wait() 方法 和 notifyAll() 方法来进行沟通的 /*** Await a newly assigned Socket from our Connector, or codenull/code* if we are supposed to shut down.*/private synchronized Socket await() {// Wait for the Connector to provide a new Socketwhile (!available) {try {wait();} catch (InterruptedException e) {}}// Notify the Connector that we have received this SocketSocket socket this.socket;available false;notifyAll();if ((debug 1) (socket ! null))log( The incoming request has been awaited);return (socket);} AttentionA1wait方法会使当前线程进入等待状态直到其他线程调用了这个对象的notify() 方法和notifyAll方法 A2下表总结了 await方法和 assign方法的程序流 WhyW1为什么 await方法要使用一个局部变量 socket而不直接将成员变量socket返回呢 因为使用局部变量可以在当前Socket对象处理完之前继续接收下一个Socket对象 W2为什么 await方法需要调用notifyAll方法呢是为了防止出现另一个Socket对象以及到达而此时变量available的值还是true的case。在这种case下连接器线程会在assign方法内的循环中阻塞知道处理器线程调用了 notifyAll方法 【5】Request对象继承了 RequestBase【6】Response对象【7】处理请求重点讨论 HttpProcessor类的 process方法1process方法执行以下3个操作 解析连接 解析请求 解析请求头2intro to process method2.1通过在Connector接口中设置缓冲区的大小任何人都可以使用连接器来设置缓冲区的大小private void process(Socket socket) { // HttpProcessor.process()boolean ok true;boolean finishResponse true;SocketInputStream input null;OutputStream output null;// Construct and initialize the objects we will needtry {input new SocketInputStream(socket.getInputStream(),connector.getBufferSize());} catch (Exception e) {log(process.create, e);ok false;}keepAlive true;while (!stopped ok keepAlive) {finishResponse true;try {request.setStream(input);request.setResponse(response);output socket.getOutputStream();response.setStream(output);response.setRequest(request);((HttpServletResponse) response.getResponse()).setHeader(Server, SERVER_INFO);} catch (Exception e) {log(process.create, e);ok false;}// Parse the incoming requesttry {if (ok) {parseConnection(socket); // step1解析连接parseRequest(input, output); // step2解析请求if (!request.getRequest().getProtocol() .startsWith(HTTP/0))parseHeaders(input); // step3解析请求头if (http11) {// Sending a request acknowledge back to the client if// requested.ackRequest(output);// If the protocol is HTTP/1.1, chunking is allowed.if (connector.isChunkingAllowed())response.setAllowChunking(true);}}} catch (EOFException e) {// Its very likely to be a socket disconnect on either the // client or the serverok false;finishResponse false;} catch (ServletException e) {ok false;try {((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_BAD_REQUEST);} catch (Exception f) {;}} catch (InterruptedIOException e) {if (debug 1) {try {log(process.parse, e);((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_BAD_REQUEST);} catch (Exception f) {;}}ok false;} catch (Exception e) {try {log(process.parse, e);((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_BAD_REQUEST);} catch (Exception f) {;}ok false;}// Ask our Container to process this requesttry {((HttpServletResponse) response).setHeader(Date, FastHttpDateFormat.getCurrentDate());if (ok) {connector.getContainer().invoke(request, response);}} catch (ServletException e) {log(process.invoke, e);try {((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);} catch (Exception f) {;}ok false;} catch (InterruptedIOException e) {ok false;} catch (Throwable e) {log(process.invoke, e);try {((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);} catch (Exception f) {;}ok false;}// Finish up the handling of the requestif (finishResponse) {try {response.finishResponse();} catch (IOException e) {ok false;} catch (Throwable e) {log(process.invoke, e);ok false;}try {request.finishRequest();} catch (IOException e) {ok false;} catch (Throwable e) {log(process.invoke, e);ok false;}try {if (output ! null)output.flush();} catch (IOException e) {ok false;}}// We have to check if the connection closure has been requested// by the application or the response stream (in case of HTTP/1.0// and keep-alive).if ( close.equals(response.getHeader(Connection)) ) {keepAlive false;}// End of request processingstatus Constants.PROCESSOR_IDLE;// Recycling the request and the response objectsrequest.recycle();response.recycle();}try {shutdownInput(input);socket.close();} catch (IOException e) {;} catch (Throwable e) {log(process.invoke, e);}socket null;}2.2然后是while循环在该循环内不断读入输入流知道HttpProcessor 实例终止抛出一个异常或连接断开// Parse the incoming requesttry { // there code are located in HttpProcessor.process() method.if (ok) {parseConnection(socket);parseRequest(input, output);if (!request.getRequest().getProtocol().startsWith(HTTP/0))parseHeaders(input);if (http11) {// Sending a request acknowledge back to the client if// requested.ackRequest(output);// If the protocol is HTTP/1.1, chunking is allowed.if (connector.isChunkingAllowed())response.setAllowChunking(true);}}} 【7.1】解析连接1parseConnection() 方法会从套接字中获取Internet地址将其赋值给 HttpRequestImpl 对象此外它还要检查是否使用了代理将Socket对象赋值给 request对象private void parseConnection(Socket socket) // HttpProcessor.parseConnection()throws IOException, ServletException {if (debug 2)log( parseConnection: address socket.getInetAddress() , port connector.getPort());((HttpRequestImpl) request).setInet(socket.getInetAddress());if (proxyPort ! 0)request.setServerPort(proxyPort);elserequest.setServerPort(serverPort);request.setSocket(socket);}【7.2】解析请求【7.3】解析请求头1默认连接器中的parseHeaders() 方法使用了 org.apache.catalina.connector.http 包内的HttpHeader类和 DefaultHeader类。HttpHeader类表示一个HTTP 请求头。HttpHeader 类使用了字符数组来避免高代价的字符串操作。DefaultHeaders类是一个final类包含了 字符数组形式的标准HTTP请求头final class DefaultHeaders {// -------------------------------------------------------------- Constantsstatic final char[] AUTHORIZATION_NAME authorization.toCharArray();static final char[] ACCEPT_LANGUAGE_NAME accept-language.toCharArray();static final char[] COOKIE_NAME cookie.toCharArray();static final char[] CONTENT_LENGTH_NAME content-length.toCharArray();static final char[] CONTENT_TYPE_NAME content-type.toCharArray();static final char[] HOST_NAME host.toCharArray();static final char[] CONNECTION_NAME connection.toCharArray();static final char[] CONNECTION_CLOSE_VALUE close.toCharArray();static final char[] EXPECT_NAME expect.toCharArray();static final char[] EXPECT_100_VALUE 100-continue.toCharArray();static final char[] TRANSFER_ENCODING_NAME transfer-encoding.toCharArray();static final HttpHeader CONNECTION_CLOSE new HttpHeader(connection, close);static final HttpHeader EXPECT_CONTINUE new HttpHeader(expect, 100-continue);static final HttpHeader TRANSFER_ENCODING_CHUNKED new HttpHeader(transfer-encoding, chunked);2parseHeaders() 方法使用while循环读取所有的HTTP 请求信息。调用request对象的 allocateHeader方法获取一个内容为空的 HttpHeader实例开始。然后该实例被传入SocketInputStream 实例的readHeader方法中private void parseHeaders(SocketInputStream input) // HttpProcessor.parseHeaders()throws IOException, ServletException {while (true) {HttpHeader header request.allocateHeader();// Read the next headerinput.readHeader(header);if (header.nameEnd 0) {if (header.valueEnd 0) {return;} else {throw new ServletException(sm.getString(httpProcessor.parseHeaders.colon));}}String value new String(header.value, 0, header.valueEnd);if (debug 1)log( Header new String(header.name, 0, header.nameEnd) value);......request.nextHeader();}}3若所有的请求头都已经读取过了则readHeader()方法不会再给 HttpHeader 实例设置name属性了。就退出parseHeader方法了if (header.nameEnd 0) {if (header.valueEnd 0) {return;} else {throw new ServletException(sm.getString(httpProcessor.parseHeaders.colon));}}【8】简单的Container 应用程序1SimpleContainer类实现了 org.apache.catalina.Container接口这样它就可以与默认连接器进行关联。 public class SimpleContainer implements Container { // just demonstrate a core method invoke.public void invoke(Request request, Response response)throws IOException, ServletException {String servletName ( (HttpServletRequest) request).getRequestURI();servletName servletName.substring(servletName.lastIndexOf(/) 1);URLClassLoader loader null;try {URL[] urls new URL[1];URLStreamHandler streamHandler null;File classPath new File(WEB_ROOT);String repository (new URL(file, null, classPath.getCanonicalPath() File.separator)).toString() ;urls[0] new URL(null, repository, streamHandler);loader new URLClassLoader(urls);}catch (IOException e) {System.out.println(e.toString() );}Class myClass null;try {myClass loader.loadClass(servlet. servletName);}catch (ClassNotFoundException e) {System.out.println(e.toString());}Servlet servlet null;try {servlet (Servlet) myClass.newInstance();servlet.service((HttpServletRequest) request, (HttpServletResponse) response);}catch (Exception e) {System.out.println(e.toString());}catch (Throwable e) {System.out.println(e.toString());}}Attention我总结了一张Tomcat默认连接器测试用例的大致调用过程/*** Await a newly assigned Socket from our Connector, or codenull/code* if we are supposed to shut down.*/private synchronized Socket await() { //HttpProcessor.awati() 方法// Wait for the Connector to provide a new Socketwhile (!available) {try {wait();} catch (InterruptedException e) {}}// Notify the Connector that we have received this SocketSocket socket this.socket;available false;notifyAll();if ((debug 1) (socket ! null))log( The incoming request has been awaited);return (socket);}对以上代码的分析AnalysisA1HttpConnector类的大致工作step1initialize方法调用该类的open方法创建服务器套接字step2start方法开启一个线程该线程中有一个while循环不断接收client发送的HTTP连接请求接着调用其类的createProcessor方法step3createProcessor方法调用其类的 newProcessor方法step4newProcessor方法创建HttpProcessorHTTP连接器的支持类HTTP请求处理器利用HttpProcessor实例开启一个线程调用 HttpProcessor.run()方法转向HttpProcessor类的run方法干货中的干货——也即当clients 发出http 连接请求后HttpConnector 在while循环中创建HttpConnector的支持类 HttpProcessorHttp处理器类并调用该类的start方法开启线程即while循环为每一个client 请求 开启一个线程进行处理多么巧妙A2HttpProcessor类的大致工作step1run方法传入套接字参数并调用process方法step2process方法依次调用 parseConnection()方法 parseRequest()方法 parseHeader() 方法上述3个方法的作用参见本文章节【7】也可以参见下面的补充调用上述三个方法后会调用连接器HttpConnector实例的关联容器的invoke方法转向container的invoke方法step3SimleContainer.invoke方法invoke方法声明为invoke(Request request, Response response)见下面的代码实例step3.1创建类加载器step3.2利用类加载器集合request中的请求URIHttpProcessor.parseReqeust解析出的请求URI加载请求的servlet创建该servlet实例并调用其service方法service方法接着就会向client发送响应信息endingpublic final class Bootstrap {public static void main(String[] args) {HttpConnector connector new HttpConnector();SimpleContainer container new SimpleContainer(); // 创建容器connector.setContainer(container); // 将该 容器 和 http连接器 相关联try {connector.initialize();connector.start();// make the application wait until we press any key.System.in.read();}catch (Exception e) {e.printStackTrace();}} }补充-Complementary beginsC1HttpProcessor.parseConnection方法会从套接字中获取internet地址端口号协议等信息 C2HttpProcessor.parseRequest方法会解析请求体的第一行请求信息请求方法——URI——协议/版本 C3HttpProcessor.parseHeader方法解析请求体中的请求头信息还会附加解析cookie信息 补充-Complementary ends 补充-Complementary2 begins在补充一个知识点request和response是何时创建的——其实在HttpProcessor 构造器中就已经创建了public HttpProcessor(HttpConnector connector, int id) {super();this.connector connector;this.debug connector.getDebug();this.id id;this.proxyName connector.getProxyName();this.proxyPort connector.getProxyPort();this.request (HttpRequestImpl) connector.createRequest();this.response (HttpResponseImpl) connector.createResponse();this.serverPort connector.getPort();this.threadName HttpProcessor[ connector.getPort() ][ id ];} public Request createRequest() { HttpRequestImpl request new HttpRequestImpl();request.setConnector(this);return (request);}public Response createResponse() {HttpResponseImpl response new HttpResponseImpl();response.setConnector(this);return (response);}补充-Complementary2 ends【9】运行应用程序9.1运行参数E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\srcjava -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot com.tomcat.chapter4.startup.Bootstrap HttpConnector Opening server socket on all host IP addresses HttpConnector[8080] Starting background thread from service from service9.2运行结果
http://wiki.neutronadmin.com/news/424747/

相关文章:

  • 网站建设找哪个平台网站开发公司哪里寻找客源
  • 河南省住房和城乡建设厅网站确认书wordpress short_open_tag
  • 东莞建设工程造价管理网站公司企业展厅设计公司
  • 教学网站模板下载wordpress修改页脚
  • 做网站是如果盈利的地方网站优势
  • 手机网站适配代码福建省建设工程招投标信息网
  • lol网站模板抚顺市城市建设档案馆网站
  • 三网一体网站建设域名没备案wordpress不能编辑文章
  • 网站开发细节wordpress微信授权访问
  • 网站服务是什么app平台制作开发
  • 自己做效果图的网站怎样自己建设网站
  • 做网站要什么步骤济南突然宣布
  • go语言做的网站免费推广手段
  • 深圳高端网站定制厦门石材网站建设
  • 竹子建站怎么样wordpress文章不分段
  • aardio 网站开发中外商贸网站建设平台
  • wordpress图床网站邯郸专业做网站哪里有
  • 新昌网站制作网站建设哪里好翰诺科技
  • 养殖类网站模板广告文案经典范例200字
  • 网站建设部工作职能专业h5网站制作
  • dede响应式网站模板下载四川省工程造价总站官网
  • 培训学校网站模板织梦网站上传保存文档
  • 找别人做网站交货时应该注意什么做网站需要会什么
  • 个人网站备案所需材料淘宝客用wordpress好吗
  • 网站建设时间怎么查询个人网站建设的小清新图片
  • 点评网站开发个人网站,可以做淘宝客吗
  • 建立了公司网站wordpress 搜索记录
  • 网站设计的主要机构有哪些网页游戏网站建设
  • 深圳品牌策划培训厦门百度seo点击软件
  • 万网主机怎么做网站如何做好品牌网站建设方案