文档章节

自己动手编写tomcat服务器(一)

yolinfeng
 yolinfeng
发布于 2015/06/19 18:02
字数 843
阅读 29
收藏 0

这篇博文来自于《how tomcat works》一书的第一章

我们的服务器程序由下列三个类组成:

     HttpServer.java

     Request.java

     Response.java

HttpServer.java是程序的入口。它的main方法创建了一个HttpServer的实例,然后调用它的await方法,此方法等待客户端的

HTTP请求,处理请求,把响应传回客户端。此服务器程序只能处理静态的资源,如HTML文件和图片文件。


我们来看看HttpServer.java的源代码

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;

public class HttpServer {
	/**
	 * WEB_ROOT是存放HTML文件的目录
	 */
	public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
	
	//关闭命令
	private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
	
	//收到关闭命令
	private boolean shutdown = false;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		HttpServer server = new HttpServer();
		server.await();

	}

	public void await() {
		ServerSocket serverSocket = null;
		int port = 8080;
		try{	
			serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); 
		}catch(IOException e){
			e.printStackTrace();
			System.exit(1);
		}
		//等待请求
		while(!shutdown){
			Socket socket = null;
			InputStream inputStream = null;
			OutputStream outputStream = null;
			try{
			
				socket = serverSocket.accept();
				inputStream = socket.getInputStream();
				outputStream = socket.getOutputStream();
				
				//创建请求对象并解析
				Request request = new Request(inputStream);
				request.parse();
				
				//创建响应对象
				Response response = new Response(outputStream);
				response.setRequest(request);
				response.sendStaticResource();
				
				//关闭socket
				if(socket != null){
					 socket.close();
				}
				  
				//检查URI是否是一个关闭命令
				shutdown = SHUTDOWN_COMMAND.equals(request.getUri());
				
			}catch(Exception e){
				e.printStackTrace();
				continue;
			}
		}
	}

}


Request.java类代表一个HTTP请求,它的构造方法传入一个InputStream输入流,该输入流来自于与客户端交流的那个socket,即ServerSocket的accept方法返回的那个socket对象。下面是Request.java类的源代码:

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

public class Request {
	private InputStream inputStream;
	private String uri;
	public Request(InputStream inputStream) {
		this.inputStream = inputStream;
	}
	
	public void parse(){
		StringBuffer request = new StringBuffer(2048);
		int i;
		byte[] buffer = new byte[2048];
		try{
			i = inputStream.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());
	}
	
	private String parseUri(String requestString){
		int index1,index2;
		index1 = requestString.indexOf(" ");
		if(index1 != -1){
			index2 = requestString.indexOf(" ",index1 + 1);
			if(index2 > index1)
				return requestString.substring(index1+1,index2);
			return null;
		}else{
			return null;
		}
	}

	public String getUri() {
		return uri;
	}

	public void setUri(String uri) {
		this.uri = uri;
	}
	
	
	

}


方法parse()用来解析HTTP请求的数据。方法parseUri()根据传入的请求数据(一个字符串)解析出HTTP请求的URI,如GET  /index.html  HTTP/1.1中的 /index.html

就是一个HTTP请求的URI,方法parseUri()是通过搜索请求的第一个空格和第二个空格间的字符串来得到URI的。


Response.java类代表一个HTTP响应,源代码如下:


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Response {
	private static final int BUFFER_SIZE = 1024;
	Request request;
	OutputStream outputStream;
	
	public Response(OutputStream outputStream) {
		this.outputStream =outputStream;
	}

	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(HttpServer.WEB_ROOT,request.getUri());
			if(file.exists()){
				fis = new FileInputStream(file);
				int ch = fis.read(bytes,0,BUFFER_SIZE);
				while(ch != -1){
					outputStream.write(bytes, 0, ch);
					ch = fis.read(bytes,0,BUFFER_SIZE);
				}
			}else{
				String errorMessage = "<h1>File not found</h1>";
				outputStream.write(errorMessage.getBytes());
			}
		}catch(Exception e){
		   System.out.println(e.toString());
		}finally{
			if(fis != null)
			fis.close();
		}
		
		
	}
	
	

}


Response类的构造方法传入一个OutputStream输出流,此输出流来自于socket的getOutputStream()方法,而此socket又来自于ServerSocket的accept方法返回的对象

Response类的sendStaticResource()方法先找到HTTP请求头的URI所代表的文件,将此文件读入到一个字节数组,再用OutputStream输出流将字节数组写入到客户端

的浏览器。如果URI所代表的文件不存在,就向浏览器写入一个错误信息。


启动HttpServer类,在浏览器中输入http://localhost:8080/index.html,(可以自己在此web工程的WebRoot根目录下新建一个index.html文件),你将看到index.html在浏览器

中显示出来。





本文转载自:http://blog.csdn.net/wenjingyu/article/details/10168187

yolinfeng
粉丝 12
博文 196
码字总数 11946
作品 0
珠海
架构师
私信 提问
tomcat实践总结

前言: 常言道,实践出真知。其实懵懵懂懂看了好几章节对tomcat的介绍,真不如自己动手实践实践,从实践中理解tomcat的基本组建及相关配置。此篇主要记录博主使用tomcat的整个配置过程~ 正文...

li690347460
2017/02/09
0
0
微服务 SpringBoot 2.0(七):使用JdbcTemplates访问Mysql

一切没有与数据库交互的网站都是假网站 —— Java面试必修 引言 在web开发服务中,开发人员要做的事情就是将数据库中的数据返回至前端页面,在第五章我们已经整合了页面,今天我们再结合数据...

阿郎_
2018/09/28
0
0
Tomcat项目部署—动态部署

之前在网上搜索过很多Tomcat项目部署的方法,在我们真正部署商用项目时,并不单单像我们平常练习时直接把目录放到webapps下即可。如何在不重启tomcat的前提下进行部署?如何在Linux这种权限操...

chace0120
2014/06/05
3K
9
OSChina 技术周刊第十一期

每周技术抢先看,总有你想要的! 前端开发 【软件】Chartist.js —— 基于 SVG 的响应式图表库 【博客】node.js构建http服务器(一) 【博客】AngularJS SEO 简易教程 【资讯】Semantic UI 1...

OSC编辑部
2014/11/30
512
0
OSChina 技术周刊第十一期 —— 每周技术抢先看

每周技术抢先看,总有你想要的! 前端开发 【软件】Chartist.js —— 基于 SVG 的响应式图表库 【博客】node.js构建http服务器(一) 【博客】AngularJS SEO 简易教程 【资讯】Semantic UI 1...

OSC编辑部
2014/11/30
5.5K
1

没有更多内容

加载失败,请刷新页面

加载更多

【2019年8月版本】OCP 071认证考试最新版本的考试原题-第13题

Choose the best answer. Examine this query: SELECT TRUNC (ROUND(156.00,-2),-1) FROM DUAL; What is the result? A) 16 B) 160 C) 150 D) 200 E) 100 Answer:D (解析:关键就是 round ......

oschina_5359
29分钟前
5
0
SolrJ 操作solr增删改查

Solr的特性包括: • 高级的全文搜索功能 • 专为高通量的网络流量进行的优化 • 基于开放接口(XML和HTTP)的标准 • 综合的HTML管理界面 • 可伸缩性-能够有效地复制到另外一个Solr搜索服...

雷开你的门
31分钟前
5
0
What’s the easiest way to teach a robot arm to stack blocks?

What’s the easiest way to teach a robot arm to stack blocks? That’s the nuanced question to which researchers at Google parent company Alphabet’s DeepMind sought answers dur......

巧克夹心
32分钟前
4
0
Vuex-dev demo npm install 时总是报phantomjs-prebuilt@2.1.14安装失败

解决方法,删除node_modules,package-lock.json以及package.json里面的 phantomjs-prebuilt。然后 npm install,最后安装phantomjs-prebuilt。 npm install phantomjs-prebuilt@2.1.14 --ig......

牧云橙
34分钟前
7
0
理解自定义starter的主要目的

自定义starter的主要功能是自动帮我们将某个JavaBean转换成SpringBean,在这个过程中,有些类的实例化会依赖其他的类,考虑到是否需要交给Spring管理,会有很多注解来辅助boot是否是实例化该...

redis缓存
41分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部