Tomcat应该都不陌生,咱们常常会把写好的代码打包放在Tomcat里并启动,而后在浏览器里就能愉快的调用咱们写的代码来实现相应的功能了,那么Tomcat是如何工做的?html
咱们启动Tomcat时双击的startup.bat文件的主要做用是找到catalina.bat,而且把参数传递给它,而catalina.bat中有这样一段话:web
Bootstrap.class是整个Tomcat 的入口,咱们在Tomcat源码里找到这个类,其中就有咱们常用的main方法:浏览器
这个类有两个做用 :1.初始化一个守护进程变量、加载类和相应参数。2.解析命令,并执行。服务器
源码不过多赘述,咱们在这里只须要把握总体架构,有兴趣的同窗能够本身研究下源码。Tomcat的server.xml配置文件中能够对应构架图中位置,多层的表示能够配置多个:多线程
即一个由 Server->Service->Engine->Host->Context 组成的结构,从里层向外层分别是:架构
好比如今有如下网址,根据“/”切割的连接就会定位到具体的处理逻辑上,且每一个容器都有过滤功能。app
下面只是简单实现效果,当浏览器访问对应地址时:socket
实现以上效果总体思路以下:网站
1.ServerSocket占用8080端口,用while(true)循环等待用户发请求。this
2.拿到浏览器的请求,解析并返回URL地址,用I/O输入流读取本地磁盘上相应文件。
3.读取文件,不存在构建响应报文头、HTML正文内容,存在则写到浏览器端。
工程文件结构和pom.xml文件:
1.HttpServer核心处理类,用于接受用户请求,传递HTTP请求头信息,关闭容器:
public class HttpServer { // 用于判断是否须要关闭容器 private boolean shutdown = false; public void acceptWait() { ServerSocket serverSocket = null; try { //端口号,最大连接数,ip地址 serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } // 等待用户发请求 while (!shutdown) { try { Socket socket = serverSocket.accept(); InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); // 接受请求参数 Request request = new Request(is); request.parse(); // 建立用于返回浏览器的对象 Response response = new Response(os); response.setRequest(request); response.sendStaticResource(); //关闭一次请求的socket,由于http请求就是采用短链接的方式 socket.close(); //若是请求地址是/shutdown 则关闭容器 if(null != request){ shutdown = request.getUrL().equals("/shutdown"); } } catch (Exception e) { e.printStackTrace(); continue; } } } public static void main(String[] args) { HttpServer server = new HttpServer(); server.acceptWait(); } }
2.建立Request类,获取HTTP的请求头全部信息并截取URL地址返回:
public class Request { private InputStream is; private String url; public Request(InputStream input) { this.is = input; } public void parse() { //从socket中读取一个2048长度字符 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]); } //打印读取的socket中的内容 System.out.print(request.toString()); url = parseUrL(request.toString()); } private String parseUrL(String requestString) { int index1, index2; index1 = requestString.indexOf(' ');//看socket获取请求头是否有值 if (index1 != -1) { index2 = requestString.indexOf(' ', index1 + 1); if (index2 > index1) return requestString.substring(index1 + 1, index2); } return null; } public String getUrL() { return url; } }
3.建立Response类,响应请求读取文件并写回到浏览器
public class Response { public static final int BUFFER_SIZE = 2048; //浏览器访问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() throws IOException { byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis = null; try { //拼接本地目录和浏览器端口号后面的目录 File file = new File(WEB_ROOT, request.getUrL()); //若是文件存在,且不是个目录 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 { //文件不存在,返回给浏览器响应提示,这里能够拼接HTML任何元素 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(); } } }
1.在WEB_INF文件夹下读取web.xml解析,经过请求名找到对应的类名,经过类名建立对象,用反射来初始化配置信息,如welcome页面,Servlet、servlet-mapping,filter,listener,启动加载级别等。
2.抽象Servlet类来转码处理请求和响应的业务。发过来的请求会有不少,也就意味着咱们应该会有不少的Servlet,例如:RegisterServlet、LoginServlet等等还有不少其余的访问。能够用到相似于工厂模式的方法处理,随时产生不少的Servlet,来知足不一样的功能性的请求。
3.使用多线程。本文的代码是死循环,且只能有一个连接,而现实中的状况是每每会有不少不少的客户端发请求,能够把每一个浏览器的通讯封装到一个线程当中。