`
愤怒的砖头
  • 浏览: 9774 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

浅析Tomcat原理(一个简单的web应用服务器)

 
阅读更多

Tomcat是一个jsp和servlet的容器,缺少了这个容器,web程序就不能得以实现。

学过Java的人都知道socket吧?tomcat其实就是一个ServerSocket服务器,一个普通的HTTP请求的过程是:

三次握手建立连接——浏览器发送请求——服务器响应


我们平时通过浏览器去访问资源的时候,需要在地址栏上输入url地址,其实你访问url地址就是你访问该服务器上的资源。为什么称作访问资源呢?我们称互联网上的各种各样的文件叫做资源,平时我们在建立一个网站的时候,需要建立那些html文件、图片文件等,都是资源,当我们请求资源的时候过程是这样子的:我们从浏览器中输入远程服务器上该资源的位置,也就是URI(统一资源定位符),当tomcat服务器接收到这个HTTP请求之后呢,就会解析报文里面的uri,得到这个Uri之后,服务器就会在webroot相应的目录下找到该资源,并且通过IO流去读取这个文件,然后把这个文件以流的形式返回给浏览器。当然,我们需要指定contentType来确定输出的是什么流,假如是普通的text/html,则返回的也就是基于浏览器解析的数据,让浏览器解析成为我们可以看到的页面。


下面我们来写一个简单的web服务器来说明:

先是一个HttpServer类:

package com.ccw.server;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import com.ccw.request.Request;
import com.ccw.response.Response;

public class HttpServer {

	private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";

	private boolean isShutdown = false;

	private int portNum = 8888;

	public void start() {
		ServerSocket serverSocket = null;
		int port = portNum;

		try {
			serverSocket = new ServerSocket(port, 1,
					InetAddress.getByName("127.0.0.1"));

		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(1);
		}

		while (!isShutdown) {
			Socket socket = null;
			InputStream is = null;
			OutputStream os = null;

			try {
				//等待请求
				System.out.println("=====等待请求======");
				socket = serverSocket.accept();
				System.out.println("=====建立请求======");
				is = socket.getInputStream();
				os = socket.getOutputStream();
				
				Request request = new Request(is);
				//解析请求
				request.parse();

				Response response = new Response(os);
				response.setRequest(request);
				//响应
				response.sendResponse();
				System.out.println("======返回响应信息=======");
				
				socket.close();
				System.out.println("======连接关闭=======");

				isShutdown = request.getUri().equals(SHUTDOWN_COMMAND);
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}

	}

	public static void main(String[] args) {
		HttpServer server = new HttpServer();
		server.start();
		System.out.println("==========启动成功=========");
	}

}
接下来分别是Request类和Response类:

Request:

此类有两个方法,parse()方法用来解析请求中的信息,此处使用字符串来存储请求报文数据,parseUri()方法则是在请求报文中解析出Uri来

package com.ccw.request;

import java.io.IOException;
import java.io.InputStream;

public class Request {

	//用来读取请求中的数据
	private InputStream is;
	private String uri;
	
	public Request(InputStream is) {
		this.is=is;
	}

	/**
	 * 解析请求
	 */
	public void parse() {
		//以字符串的形式存储request报文
		StringBuffer request=new StringBuffer(2048);
		int i;
		byte[] buffer=new byte[2048];
		try {
			i=is.read(buffer);
		} catch (IOException e) {
			e.printStackTrace();
			i=-1;
		}
		for(int j=0;j<i;j++){
			request.append((char)buffer[j]);
		}
		System.out.println(request.toString());
		uri=parseUri(request.toString());
		
	}

	/**
	 * 解析uri
	 * @param requestStr
	 * @return
	 */
	private String parseUri(String requestStr) {
		int index1,index2;
		index1=requestStr.indexOf(' ');
		if(index1!=-1){
			index2=requestStr.indexOf(' ', index1+1);
			if(index2>index1){
				return requestStr.substring(index1,index2);
			}
		}
		return null;
	}

	public String getUri() {
		return this.uri;
	}

}

Response:

此类只有一个方法sendResponse(),用来响应请求,返回数据,根据请求中的uri到webroot目录下寻找资源,如果找到,使用输出流写出该资源文件;否则,使用输出流写出页面找不到的页面。

package com.ccw.response;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import com.ccw.request.Request;
import com.ccw.server.Constants;

public class Response {
	
	//一次读取的长度
	private static final int BUFFER_SIZE=1024;
	
	Request request;
	
	//用来写数据返回到页面
	OutputStream os;
	
	public Response(OutputStream os) {
		this.os=os;
	}

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

	/**
	 * 响应请求
	 */
	public void sendResponse() {
		byte[] bytes=new byte[BUFFER_SIZE];
		FileInputStream fis=null;
		try {
			//在webroot目录下寻找所请求的资源
			File file=new File(Constants.WEB_ROOT, request.getUri().trim());
			System.out.println(Constants.WEB_ROOT+request.getUri().trim());
			//如果资源存在,则返回数据
			if(file.exists()){
				fis=new FileInputStream(file);
				int ch=fis.read(bytes,0,BUFFER_SIZE);
				while(ch!=-1){
					os.write(bytes, 0, BUFFER_SIZE);
					ch=fis.read(bytes, 0, BUFFER_SIZE);
				}
			//否则返回404错误
			}else{
				String errorMsg="HTTP/1.1 404 File Not Found\r\n"+
			"Content-Type:text/html\r\n"+"Content-Length:23\r\n"+
						"\r\n<h1>File Not Found</h1>";
				os.write(errorMsg.getBytes());
			}
		} catch (Exception e) {
			System.out.println(e.toString());
			e.printStackTrace();
		}finally{
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
	}


}

下面的是常量类:

package com.ccw.server;

import java.io.File;

public class Constants {

	public static final String WEB_ROOT = System.getProperty("user.dir")
			+ File.separator + "webroot";;

}
写完了这几个类之后,一个简单的web应用服务器就完成了啦

现在我们需要测试一下,首先在改项目下新建一个webroot文件夹来存放资源文件,然后在webroot目录下建立一个index.html文件,内容自定,然后执行HttpServer文件,在浏览器中输入http://localhost:8888/index.html,然后就可以访问啦。

这只是一个简单的web应用服务器,tomcat涉及到的知识远远不止这些,多用户访问还涉及到多线程编程,性能调优涉及到线程池等等。。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics