Tomcat should be familiar, we often write code packaged in Tomcat and start, and then in the browser can happily call our code to implement the corresponding function, so how does Tomcat work?

I. Working principle of Tomcat

Bat file to find catalina.bat and pass parameters to it. Catalina. bat:

Source code but more verbose, we only need to grasp the overall structure here, interested students can study their own source code. The Tomcat server. XML configuration file can correspond to the location in the architecture diagram. Multiple layers of representation can be configured:

Server: The top-level element of Server Tomcat, which contains everything.

Service: A collection of engines, including definitions for thread pools Executor and Connector.

Engine: An Engine represents a complete Servlet Engine that receives requests from the Connector and decides which Host to pass on to.

Container(Container) : Host, Context, Engine, and Wraper all inherit from the Container interface and are containers.

Connector: Connect a Service to a Container, register a Service, and forward requests from clients to the Container.

Host: virtual Host, the so-called “a virtual Host” can be simply understood as “a website”.

Context: A Web application, a Context is for a Web application.

The Context container directly manages the running of the Servlet, which is wrapped in a StandardWrapper class to run. Wrapper, which manages the loading, initialization, execution, and resource recovery of a Servlet, is the lowest level container.

For example, with the following urls, links cut by “/” are directed to specific processing logic, and each container has filtering capabilities.

Second, Tomcat implementation ideas

The following is a simple implementation, when the browser visits the corresponding address:

2. Get the browser request, parse it, and return the URL address. Use the I/O input stream to read the corresponding file on the local disk.

3. Read the file. If no response header or HTML text exists, the file is written to the browser.

Three, implement Tomcat

Project file structure and POM.xml file:

public class HttpServer {
  // It is used to determine whether the container needs to be closed
  private boolean shutdown = false;
  
  public void acceptWait(a) {
    ServerSocket serverSocket = null;
    try {
        // Port number, maximum number of links, IP address
      serverSocket = new ServerSocket(8080.1, InetAddress.getByName("127.0.0.1"));
    }
    catch (IOException e) {
        e.printStackTrace();
        System.exit(1); 
    }
    // Wait for the user to send the request
    while(! shutdown) {try {
        Socket socket = serverSocket.accept();
        InputStream is = socket.getInputStream();
        OutputStream  os = socket.getOutputStream();
        // Accept request parameters
        Request request = new Request(is);
        request.parse();
        // Create an object to return to the browser
        Response response = new Response(os);
        response.setRequest(request);
        response.sendStaticResource();
        // Close the socket for a request because HTTP requests are short connections
        socket.close();
        // Close the container if the request address is /shutdown
        if(null! = request){ shutdown = request.getUrL().equals("/shutdown"); }}catch (Exception e) {
          e.printStackTrace();
          continue; }}}public static void main(String[] args) {
        HttpServer server = newHttpServer(); server.acceptWait(); }}Copy the code

2. Create a Request class, obtain all information about the HTTP Request header, intercept the URL address and return:

public class Request {
  private InputStream is;
  private String url;

  public Request(InputStream input) {
    this.is = input;
  }
  public void parse(a) {
    // Read a 2048 character from the socket
    StringBuffer request = new StringBuffer(Response.BUFFER_SIZE);
    int i;
    byte[] buffer = new byte[Response.BUFFER_SIZE];
    try {
      i = is.read(buffer);
    }
    catch (IOException e) {
      e.printStackTrace();
      i = -1;
    }
    for (int j=0; j<i; j++) {
      request.append((char) buffer[j]);
    }
    // Prints the contents of the socket read
    System.out.print(request.toString());
    url = parseUrL(request.toString());
  }

  private String parseUrL(String requestString) {
    int index1, index2;
    index1 = requestString.indexOf(' ');// See if the socket has a value for the request header
    if(index1 ! = -1) {
      index2 = requestString.indexOf(' ', index1 + 1);
      if (index2 > index1)
        return requestString.substring(index1 + 1, index2);
    }
    return null;
  }

  public String getUrL(a) {
    returnurl; }}Copy the code

3. Create a Response class to read the file and write it back to the browser

public class Response {
  public static final int BUFFER_SIZE = 2048;
  // The browser accesses the file on drive D
  private static final String WEB_ROOT ="D:";
  private Request request;
  private OutputStream output;

  public Response(OutputStream output) {
    this.output = output;
  }
  public void setRequest(Request request) {
    this.request = request;
  }

  public void sendStaticResource(a) throws IOException {
    byte[] bytes = new byte[BUFFER_SIZE];
    FileInputStream fis = null;
    try {
        // Concatenate the local directory with the directory after the browser port number
      File file = new File(WEB_ROOT, request.getUrL());
      // If the file exists and is not a directory
      if(file.exists() && ! file.isDirectory()) { fis =new FileInputStream(file);
        int ch = fis.read(bytes, 0, BUFFER_SIZE);
        while(ch! = -1) {
          output.write(bytes, 0, ch);
          ch = fis.read(bytes, 0, BUFFER_SIZE); }}else {
           // The file does not exist, returns a response to the browser, where you can concatenate any HTML element
          String retMessage = "<h1>"+file.getName()+" file or directory not exists</h1>";
          String returnMessage ="HTTP/1.1 404 File Not Found\r\n" +
                  "Content-Type: text/html\r\n" +
                  "Content-Length: "+retMessage.length()+"\r\n" +
                  "\r\n"+ retMessage; output.write(returnMessage.getBytes()); }}catch (Exception e) {
      System.out.println(e.toString() );
    }
    finally {
      if(fis! =null) fis.close(); }}}Copy the code

4. Extension points

1. Read the web. XML parsing in the WEB_INF folder, find the corresponding class name based on the request name, create objects based on the class name, and use reflection to initialize configuration information, such as the Welcome page, Servlet, servlet-mapping, filter, listener, and start loading level.

2. Abstract Servlet classes to transcode request and response services. There will be a lot of requests coming in, which means we should have a lot of servlets, such as registerServlets, Loginservlets, and many other accesses. You can use an approach similar to the factory pattern to generate many servlets at any time to satisfy different functional requests.

3. Use multiple threads. The code in this article is in an infinite loop and can only have one link, whereas the reality is that many, many clients make requests, encapsulating each browser’s communication into a single thread.