Tomcat作为开源的轻量级WEB服务器,虽然不是很适合某些大型项目,但是它开源,读其源代码可以很好的提高我们的编程功底和设计思维。Tomcat中用到了很多比较好的设计模式,其中代码风格也很值得我们去效仿。前阵子看了Tomcat源码分析这本书,特此过来分享分享自己的学习过程记录。说得不好,大神不要喷我。

  也不废话了,直入主题上代码。Tomcat是什么,Tomcat是一个web服务器,能够接收请求,作出响应。接收请求,作出响应让我们联想到Socket编程。我们可以起一个线程服务ServerSocket来监听本机的8080端口(可配置),然后就可以在浏览器上访问http://localhost:8080/index.html,这个时候就可以通过socket的inputstream获取到浏览器封装的HTTP请求了,然后就可以针对这个请求来大做文章。以下是服务端的代码

 package cn.tim.server.core;

 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; /**
* HTTP服务器,主类
* @author TIM
*
*/
public class HttpServer { /**
* 端口
*/
public int PORT = 8080; /**
* 关闭指令
*/
public final static String SHUTDOWN = "SHUTDOWN"; /**
* webroot根目录
*/
public static final String WEB_ROOT =
System.getProperty("user.dir") + File.separator + "WebRoot"; public static void main(String[] args) { new HttpServer().await(); } /**
* 线程监听
*/
private void await() { ServerSocket server = null;
try {
server = new ServerSocket(PORT,1,
InetAddress.getByName("127.0.0.1"));
} catch (Exception e) {
e.printStackTrace();
} boolean shutdown = false;
while(!shutdown) {
Socket client = null;
InputStream in = null;
OutputStream out = null;
try {
// 获取到请求socket
client = server.accept();
in = client.getInputStream();
out = client.getOutputStream(); // 生成request同时解析请求
Request request = new Request(in);
request.parse(); // 生成response
Response response = new Response(out);
response.setRequest(request);
// 根据资源定位符发送对应资源
response.sendStaticResource();
client.close(); shutdown = request.getUri().equals(SHUTDOWN);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
continue;
} } } }

  既然服务端HttpServer都出来了,Request都干些什么,request顾名思义,请求肯定是封装请求的一个JAVA类,肯定要能够解析HTTP请求,例如访问静态资源,就得获取到静态资源的资源定位符uri。

  HTTP请求Request类:

 GET /index.html HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MALCJS)
Accept-Encoding: gzip, deflate
Host: localhost:8080
DNT: 1
Connection: Keep-Alive
Cookie: principal=user:admin__password:admin
 package cn.tim.server.core;

 import java.io.IOException;
import java.io.InputStream; /**
* 封装请求
* @author TIM
*
*/
public class Request { /**
* 请求输入流
*/
private InputStream in; /**
* 资源定位符
*/
private String uri; /**
* 初始化request,传入socket输入流
* @param in
*/
public Request(InputStream in) {
this.in = in;
} /**
* 根据请求字符串解析请求
*/
public void parse() { try {
byte[] bytes = new byte[2048];
int i = in.read(bytes); StringBuffer buffer = new StringBuffer(2048);
for(int j=0; j<i; j++) {
buffer.append((char)bytes[j]);
}
System.out.println(buffer.toString());
uri = parseUri(buffer.toString());
System.out.println(uri);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } /**
* 解析出资源定位符uri,实际上就是用字符串分拆获取到GET /index.html HTTP/1.1中的/index,html
* @return
*/
private String parseUri(String requestString) { int index1 = requestString.indexOf(" ");
if(index1 != -1) {
int index2 = requestString.indexOf(" ", index1+1);
if(index2>index1) {
return requestString.substring(index1+1, index2);
}
}
return null;
} public InputStream getIn() {
return in;
} public String getUri() {
return uri;
} }

  获取到资源定位符,接下来就是根据资源定位符来作出相应,当然实际的Tomcat处理方式肯定是很复杂的,我们只模仿其中简单的方式,访问静态资源。

  Response类:

 package cn.tim.server.core;

 import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; public class Response { /**
* 输出
*/
private OutputStream out; /**
* 缓冲大小
*/
public final static int BUFFER_SIZE = 2048; /**
* 请求,根据请求作出对应的响应
*/
private Request request; public Response(OutputStream out) {
this.out = out;
} /**
* 发送静态资源
*/
public void sendStaticResource() { byte[] bytes = new byte[BUFFER_SIZE];
InputStream in = null;
try {
File file = new File(HttpServer.WEB_ROOT, request.getUri());
// 请求的资源存在
if(file.exists()) {
in = new FileInputStream(file);
int ch;
if((ch=in.read(bytes, 0, BUFFER_SIZE))!=-1) {
out.write(bytes, 0, ch);
}
}
// 请求资源不存在报404
else {
String errorMessage = "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>";
out.write(errorMessage.getBytes());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(in!=null)
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } public void setRequest(Request request) {
this.request = request;
} }

  这样,一个简单的Web服务器就实现了,可以访问静态资源,直接在浏览器上访问,没有找到对应的资源还可以报404错误。今天就写到这里,继续努力。。。

  

Tomcat源码学习记录--web服务器初步认识的更多相关文章

  1. Tomcat源码学习(1)

    Tomcat源码学习(1) IntelliJ IDEA 17.3.3 导入 Tomcat 9.0.6源码 下载源码 tomcat_9.0.6 启动 IDEA. 点击 Open,选择刚才下载的文件解压后 ...

  2. Tomcat源码学习

    Tomcat源码学习(一) 转自:http://carllgc.blog.ccidnet.com/blog-htm-do-showone-uid-4092-type-blog-itemid-26309 ...

  3. 【Tomcat源码学习】-1.概述

    Tomcat是用java语言开发的一个Web服务器,最近花了差不多两周时间对Tomcat 9.0源码进行了一遍学习,由于知识储备有限,也只是理解了一个大概,下面就由我来给大家分享一下我对Tomcat的 ...

  4. hashMap源码学习记录

    hashMap作为java开发面试最常考的一个题目之一,有必要花时间去阅读源码,了解底层实现原理. 首先,让我们看看hashMap这个类有哪些属性 // hashMap初始数组容量 static fi ...

  5. Tomcat源码学习 - 环境搭建

    一. 源码下载 PS: 多图预警 在开始阅读源码之前,我们需要先构建一个环境,这样才能便于我们对源码进行调试,具体源码我们可以到官网进行下载(这里我以8.5.63版本为例). 二. 项目导入 下载并解 ...

  6. Tomcat源码学习一

    这段时间工作不太忙,所以抽时间学习了TOMCAT, TOMCAT实际就是负责保持TCP连接传递到部署的项目中.浏览器实质就是TCP发送器.将用户的请求封装成TCP发送请求.当然格式是双方协定的.使用的 ...

  7. java内置线程池ThreadPoolExecutor源码学习记录

    背景 公司业务性能优化,使用java自带的Executors.newFixedThreadPool()方法生成线程池.但是其内部定义的LinkedBlockingQueue容量是Integer.MAX ...

  8. redux-thunk 源码学习记录

    redux触发store更新,使用的dispatch(action),在关于createStore的源码解读中可以看到,store.dispatch限制了action必须是一个纯对象.是为了保持red ...

  9. selenium expected_conditions 源码学习记录

    #expected_conditions模块收集了一系列的场景判断方法 #源码地址 # https://seleniumhq.github.io/selenium/docs/api/py/_modul ...

随机推荐

  1. HDU-1395 2^x mod n = 1

    http://acm.hdu.edu.cn/showproblem.php?pid=1395 怎样取余是关键.. 2^x mod n = 1 Time Limit: 2000/1000 MS (Jav ...

  2. HDU 1162 Eddy's picture

    坐标之间的距离的方法,prim算法模板. Eddy's picture Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32 ...

  3. 点分治练习:不虚就是要AK

    [题面] 不虚就是要AK(czyak.c/.cpp/.pas) 2s 128M czy很火.因为又有人说他虚了.为了证明他不虚,他决定要在这次比赛AK. 现在他正在和别人玩一个游戏:在一棵树上随机取两 ...

  4. [转]在 Mac OS X 终端里使用 Solarized 配色方案

    相信长期浸泡在终端和代码的小伙伴们都有一套自己喜爱的配色方案.以前一直在用简单.适合阅读的 Terminal.app 配色方案,换到 MacBook Pro with Retina display 后 ...

  5. 【BZOJ-1901】Dynamic Rankings 带修主席树

    1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7292  Solved: 3038[Su ...

  6. sublime 汉化及注册

    首先安装 package control https://packagecontrol.io/installation 网站上面有详细说明 安装以后快捷键 ctrl +shift+p   输入ip  ...

  7. .net core 使用DES加密字符串

    找了很久,都是用的第三方的插件处理,但是第三方的插件不兼容.net core中内置包. 接下来分享自己的方法: 1.创建一个加密方法类:SecurityHelper. public class Sec ...

  8. [C++基础]关键词volatile

    volatile概念 volatile 是易变的.不稳定的意思. volatile关键字和const 一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统.硬件或者其它 ...

  9. leetCode 53.Maximum Subarray (子数组的最大和) 解题思路方法

    Maximum Subarray  Find the contiguous subarray within an array (containing at least one number) whic ...

  10. SVG(可扩展矢量图)系列教程

    本系列教程同步至博客www.waylau.com 从新往久排序,持续更新 SVG与JS交互实例之画板 SVG <marker>创建箭头 SVG实例之中国地图 SVG实例之电力开关 SVG ...