Objective: In this article, I want to understand how the connector transfers the http request to the container after it arrives at tomcat?
An httpprocesctor thread has been started in the previous section, and a fixed number of HttpProcessor threads have also been started. HttpConnector is used to wait for an http connection. After an http connection is obtained, it is handed over to an HttpProcessor thread. Next, let's take a look at how httpprocesctor gets connected and how HttpProcessor handles it. After the HttpConnector thread is started (you know how to start it in the previous section), wait cyclically in its run method:
[Java]
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 );
}
// Configure y the threadStop () method that we have shut ourselves down
Synchronized (threadSync ){
ThreadSync. policyall ();
}
}
The key here is socket = serverSocket. accept (); and processor. assign (socket); in the loop, serverSocket. accept (); receives the http request, assigns it to the socket, and finally sends it to one processor for processing. Here, processor is not instantiated when necessary, but has several processor at HttpConnector initialization. In httpConnector, there is such a statement:
[Java]
Private Stack processors = new Stack ();
It indicates that httpConnector contains a stack containing the HttpProcessor object, which can be taken out as needed. Let's take a look at the createProcessor function:
[Java]
Private HttpProcessor createProcessor (){
Synchronized (processors ){
If (processors. size ()> 0 ){
Return (HttpProcessor) processors. pop (); // a processor is displayed from the processors stack.
}
If (maxProcessors> 0) & (curProcessors <maxProcessors )){
Return (newProcessor ());
} Else {
If (maxProcessors <0 ){
Return (newProcessor ());
} Else {
Return (null );
}
}
}
}
Next, the processor. assign (socket); remember that this method is asynchronous and does not need to be processed by HttpProcessor. Therefore, HttpConnector can continuously pass in Http requests. There are two important methods in HttpProcessor, these two methods coordinate and process the socket sent from HttpConnector:
[Java]
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 your y our thread
This. socket = socket;
Available = true;
Policyall ();
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 ){
}
}
// Configure y the Connector that we have received this Socket
Socket socket = this. socket;
Available = false;
Policyall ();
If (debug> = 1) & (socket! = Null ))
Log ("The incoming request has been awaited ");
Return (socket );
}
Let's take a look at the run method of HttpProcessor:
[Java]
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. policyall ();
}
}
Obviously, at the beginning of its run method, the above await method is called to wait (because the available variable is false at the beginning), so HttpProcessor will always be blocked, until there is a thread to wake it up. When processor. assign (socket) is called from HttpConnector, the socket is passed to the HttpProcessor object, and available is set to true. notifyAll () is called to wake up the processor thread to process the socket. At the same time, in the await method, available is set to false, so it is returned to the initial state, that is, the socket can be accepted again.
The socket processing method here is process (socket), which has two main functions: 1. parse the socket, that is, parse the http request, including the request Method and request protocol, to fill the request, response object (not very familiar with the requests that are frequently used in servlet and jsp development. The response object comes from here ). 2: input the request and response object to the container bound to HttpConnector, so that the container can call the invoke method for processing. The main code of the process method is as follows: www.2cto.com
[Java]
Private void process (Socket socket ){
Input = new SocketInputStream (socket. getInputStream (),
Connector. getBufferSize ());
// Parse the connection address, port or something
ParseConnection (socket );
// Parse the first line of the Request Header, namely: method, protocol, uri
ParseRequest (input, output );
If (! Request. getRequest (). getProtocol ()
. StartsWith ("HTTP/0 "))
ParseHeaders (input); // parse the http Header
........................................ ......
Connector. getContainer (). invoke (request, response );
........................................ .....
}
Author: haitao111313