This is the 23rd day of my participation in the August More Text Challenge.More challenges in August

preface

This is a book note from howTomcatWork. Here are some personal notes based on the book.

Book Address:

Link: pan.baidu.com/s/1jazo55sA… Extract code: LP96 — from Baidu network disk super member V6 share

Personal assessment

Nothing to say, tomcat author wrote a book, read the sea Amoy incredibly to more than 500 really scared. Although the code uses a Version of Tomcat 5, you can basically understand the internal workings of Tomcat. You can also see how the author upgraded to what Tomcat looks like today with a dozen lines of chicken server code.

This article is a personal record of some notes according to the book, the middle logic is not necessarily coherent, because some of the content is too basic to record the value, so I selected some personal concerns.

How does a simple Servlet work

  1. The Request object is created and the HTTP Request information is parsed, encapsulating the details of this information with the Request object

Specific interface:

Javax.mail. Servlet. ServletRequest or javax.mail. Servlet. HTTP. ServletRequest

  1. Create a Response object, which encapsulates the real data required by the customer and the relevant information of the Response body

Javax.mail. Servlet. ServletResponse or javax.mail. Servlet. HTTP. ServletResponse

  1. The servletserviceMethod that parses the request header and creates a response to pass the data back to the client

Basic structure of Tomcat

Tomcat basically splits the server into two parts, one called the container and the other called the connector

The connector

What it does: Construct a ==request== and == Response == object for each HTTP request received

The container

Function: Receives the connector request and responds to the corresponding client according to the service method

The main differences between Tomcat 4 and 5

  • Tomcat 5 supports Servlet 2.4 and JSP 2.0 specifications, while Tomcat 4 supports Servlet 2.3 and JSP 1.2.

  • Tomcat 5 has some more efficient default connectors than Tomcat 4.

  • Tomcat 5 shares a daemon thread, whereas Tomcat 4 components have their own daemon thread. Therefore, Tomcat 5 consumes fewer resources at this point.

  • Tomcat 5 does not require a mapper component to find child components, thus simplifying the code.

Build the simplest Web application

Build the object

The code below is easy to read, no need to do your own experiments

HttpServer

Use to build a server while establishing a serverSocket waiting for a link

  • callhttprequest.parse()methods

The code is as follows:

public class HttpServer {

    /** * closes the container's request path */
    private static final String SHUTDOWN = "/SHUTDOWN";

    /** * Static resource root path */
    public static final String WEBROOT = System.getProperty("user.dir") + File.separator + "webroot";

    /** * Whether to turn off the flag */
    private boolean SHUTDOWN_FLAG = false;

    public static void main(String[] args) {
        new HttpServer().await();
    }

    /** * Specifies the server method to wait for the socket request */
    public void await(a) {
        // The default port is 8080
        int port = 8080;
        String host = "127.0.0.1";
        ServerSocket serverSocket = null;
        try {
            // Create socket
            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }

        while(! SHUTDOWN_FLAG) {try {
                // Wait for a socket
                Socket accept = serverSocket.accept();
                HttpRequest httpRequest = new HttpRequest(accept.getInputStream());
                // Process the request data
                httpRequest.parse();
                // Create a response object to process the response information
                HttpResponse httpResponse = new HttpResponse(accept.getOutputStream());
                // Set the static resource
                httpResponse.setRequest(httpRequest);
                httpResponse.setResource();
                // Closed socket
                accept.close();
                // Check whether the request Url is /shutdown
                SHUTDOWN_FLAG = httpRequest.getUri().equalsIgnoreCase(SHUTDOWN);
            } catch (IOException e) {
                e.printStackTrace();
                continue; }}}}Copy the code

HttpRequest

The httpServer request InputStream is used to parse the request content and decompose the request URI

Use the parse() method to parse the request information into a StringBuffer

Use parseUri(STR) to intercept the request URI of the request information and set it to the property

public class HttpRequest {

    /** * The buffer size is 1M */
    private static final int BUFFER_COUNT = 1024;

    /** * Request path */
    private String uri;

    /** * Request flow */
    private InputStream inputStream;

    public HttpRequest(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    /** * inputStream parses the content */
    public void parse(a) {
        // String buffer pool
        StringBuffer stringBuffer = new StringBuffer(BUFFER_COUNT);

        byte[] byteBuffer = new byte[BUFFER_COUNT];

        if (inputStream == null) {
            System.err.println("Socket not found");
            return;
        }

        int read = 0;
        try {
            // Read data into byte array
            read = inputStream.read(byteBuffer);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        // Read data from the byte array into a stringBuffer
        for (int i = 0; i < read; i++) {
            stringBuffer.append((char)byteBuffer[i]);
        }
        / / print stringbuffer
        System.err.println(stringBuffer.toString());
        / / get a uri
        uri = parseUri(stringBuffer.toString());
    }

    /** * parses the request to get the request Uri *@paramRequestString Specifies the URI to process
    public String parseUri(String requestString){
        // create index1 and 2
        int index1, index2;
        // Get the first blank line
        index1 = requestString.indexOf(' ');
        if(index1 ! = -1) {// start with index1
            index2 = requestString.indexOf(' ', index1 + 1);
            if(index2 > index1){
                // Get the request path
                return requestString.substring(index1 + 1, index2); }}return null;

    }


    public String getUri(a) {
        returnuri; }}Copy the code

HttpResonse

The httpServer request outputStream is used to retrieve the input stream and return the data to the client

The key method is setResouces, which gets the request Uri and reads the file using file

public class HttpResponse {

    /** * return the corresponding message to request */
    private HttpRequest request;

    /**
     * 输出流
     */
    private OutputStream outputStream;

    /** * Buffer size */
    private static final int BUFFER_COUNT = 1024;


    public HttpResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    /** * Set the static resource */
    public void setResource(a) throws IOException {
        String errMsg = "404 msg";
        // Byte cache area
        byte[] bytes = new byte[BUFFER_COUNT];
        // Read static resources
        File file = new File(HttpServer.WEBROOT, request.getUri());
        if (file.exists()) {
            / / file stream
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                // Read bytes
                int ch = fileInputStream.read(bytes, 0, BUFFER_COUNT);
                / / output
                while(ch ! = -1) {
                    / / write down
                    outputStream.write(bytes, 0, ch);
                    // Read data repeatedly into the buffer
                    ch = fileInputStream.read(bytes, 0, BUFFER_COUNT); }}catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(outputStream ! =null) { outputStream.close(); }}}else {
            try {
                outputStream.write(errMsg.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(outputStream ! =null) { outputStream.close(); }}}}/** * set request **@param httpRequest
     */
    public void setRequest(HttpRequest httpRequest) {
        this.request = httpRequest; }}Copy the code

Basic steps:

Here are the basic interaction steps of the code:

  1. Create an HttpServer object
  2. Bind ports and hosts to establish socket connections
  3. accept()Method waits for the request, blocking the current thread
  4. Create the Reuqest request object
  5. To obtaininputstream Parsing request information
  6. Gets the Request to the URI and sets it to the Request object
  7. Create a Response response object
  8. Set the request for the response object, get the URI, and use Io to read the request to the corresponding file
  9. outputstreamParses the file stream data and returns it to the client using write
  10. Closing the stream whether it succeeds or fails (important)

Supplementary content:

Here we focus on some knowledge about sockets

ServerSocket

Another important attribute of the server socket is the backlog, which is the == maximum queue length of incoming connection requests == before the server socket starts == reject == incoming requests.

ParseUri () handles the logic

GET/index. HTTP / 1.1 HTML. The parse method reads the entire byte stream from the InputStream of the socket passed to the Requst object and stores the byte array in a buffer. It then fills a StringBuffer object with bytes of the buffer byte data and passes the string representing the StringBuffer to the parseUri method.

The operation of an Http request to a servlet

When the servlet is called for the first time, the servlet class is loaded and the init method of the servlet is called (only once).

  • For each request, construct a javax.mail servlet. The ServletRequest instance and a javax.mail servlet. The ServletResponse instance.
  • Call the service method of the servlet, passing both a ServletRequest and a ServletResponse object.
  • When the servlet class is closed, call the destroy method of the servlet and uninstall the servlet class.

The first servlet container in this chapter is not fully functional. As a result, she can’t run anything but very simple servlets, and she doesn’t call the init and destroy methods of servlets. Instead it does the following:

  • Wait for an HTTP request.
  • Construct a ServletRequest object and a ServletResponse object.
  • If the request requires a static resource, call the Process side of the StaticResourceProcessor instance

Method, passing both a ServletRequest and a ServletResponse object.

  • If the request requires a servlet, load the servlet class and call the servlet’s service method.

Both ServletRequest and ServletResponse objects are passed

StringManager

Features:

  1. Use the singleton pattern
  2. Each instance reads a properties file corresponding to the package
  3. The StringManager class is designed to be a Single Instance of StringManager that can be shared by all classes in the package
  4. The getManager() method is synchronously decorated and the Manager is managed using hashTable (tomcat4)

Core method interpretation

SocketInputStream: A socket read stream used to process various parameters in Http requests. Lazy load is used to read the stream for efficiency

  1. Reclaim check flow data
  2. Check for empty lines and throw a closing exception if -1 occurs
  3. Gets the servlet method name
    1. If the buffer is full, expand
      1. We’re at the end of the internal buffer
      2. If the end of the buffer is reached, the pointer is repositioned
    2. There is a key point here: System.arrayCopy is used to extend buffers
  4. Read the agreement

Module to explain

Explanation of some modules.

Parsing the head

  • You can construct an instance of HttpHeader by using the class’s no-argument constructor.
  • Once you have an instance of HttpHeader, you can pass it to SocketInputStream’s readHeader

Methods. If there is a header to read, the readHeader method will populate the HttpHeader object accordingly. If there are no more headers to read, the HttpHeader instance’s nameEnd and valueEnd fields will be set to zero.

  • To get the name and value of the header, use the following method:
  • String name = new String(header.name, 0, header.nameEnd);
  • String value = new String(header.value, 0, header.valueEnd);

starter

  • Start the application

  • The connector

  • Create an HttpRequest object

  • Create an HttpResponse object

  • Static resource handlers and servlet handlers

  • Run the application

The Startup module has only one class, Bootstrap, used to start applications. The classes of the Connector module can be divided into five groups:

  • Connector and its supporting classes (HttpConnector and HttpProcessor).

  • Refers to the HTTP request class (HttpRequest) and its helper classes.

  • The class that refers to the HTTP response (HttpResponse) and its helper classes.

  • The Facade class (HttpRequestFacade and HttpResponseFacade).

  • Constant class

Problems and Solutions

How to avoid expensive operations such as getParamMap and getAttribute when servlet calls connector without request parameters?

Tomcat’s default connector (and the connector for the application in this chapter) tries to be more efficient by not parsing the parameters until the servlet really needs it

Small knowledge supplement

  1. The print method does not refresh the output when System prints.
  2. Within a servlet container, the place where a classloader can find servlets is called a repository.
  3. The details of the Request object are hidden from the interior of setvlet calls, but can still communicate with each other when parsing. The getUri() method is secured by wrapping the interface with a layer of faced

conclusion

The first chapter of the book is relatively simple, and the subsequent chapters will gradually become more difficult to code, and the use of many design patterns will require a lot of reading and understanding

Write in the last

The purpose of this note is to let more people know about this book, this book is a god book, after all, the development of the original author wrote his own things is no doubt first-hand knowledge.