首先我为大家推荐一本书:How Tomcat Works。这本书讲的很详细的,虽然实际开发中我们并不会自己去写一个tomcat,但是对于了解Tomcat是如何工作的还是很有必要的。





  • Servlet容器是如何工作的

servlet容器是一个复杂的系统。不过,一个servlet容器要为一个servlet的请求提供服务,基本上有三件事要做:

1,创建一个request对象并填充那些有可能被所引用的servlet使用的信息,如参数、头部、 cookies、查询字符串、 URI 等等。一个 request 对象是javax.servlet.ServletRequest 或 javax.servlet.http.ServletRequest 接口的一个实例。

2,创建一个response对象,所引用的servlet使用它来给客户端发送响应。一个 response对象 javax.servlet.ServletResponse 或 javax.servlet.http.ServletResponse 接口的一个实例。

3,调用servlet的service方法,并传入 request 和 response 对象。在这里servlet会从 request 对象取值,给response写值。

  • Catalina 架构

Catalina是一个非常复杂的,并优雅的设计开发出来的软件,同时它也是模块化的。基于“Servlet 容器是如何工作的” 这个问题,我们可以把Catalina看成是由两个主要模块所组成的:连接器(connector) 和容器(container) 。多个连接器对应一个容器,然后放在一起组成一个service对外提供服务。连接器是用来“ 连接” 容器里边的请求的。它的工作是为接收到每一个HTTP请求构造一个request 和 response对象。然后它把流程传递给容器。容器从连接器接收到requset和response对象之后调用servlet的service方法用于响应。值得注意的是,这个描述仅仅是冰山一角而已。这里容器做了相当多事情。例如,在它调用servlet的service方法之前,它必须加载这个servlet,验证用户
(假如需要的话) ,更新用户会话等等。一个容器为了处理这个进程使用了很多不同的模块,这也并不奇怪。例如,管理模块是用来处理用户会话,而加载器是用来加载servlet类等等。

现在我自己模拟了一个简单的web服务器,如果下面这些代码很容易的理解了的话,那么对于web容器是如何工作的就基本没啥大问题了。我先简单的说下:web服务器就是在某一台虚拟主机上建立一个特定端口的服务器端socket,然后一直等待连接进来,一旦有连接连进来就new一个request和一个response,然后按照HTTP协议去解析request里面的请求参数,然后找到实际的资源文件,通过IO来读写,最后用response也按照HTTP协议去返回给客户端,就这样子就完成了一次请求和相应。下面的代码是入门级的一个web服务器,代码如下:

package linkin;

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; /**
* @author LinkinPark
* @Date 2015-3-11
* Http服务器。
*/
public class HttpServer
{
/**
* WEB_ROOT is the directory where our HTML and other files reside. For this
* package, WEB_ROOT is the "webroot" directory under the working directory.
* The working directory is the location in the file system from where the
* java command was invoked.
*
*/
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
// shutdown command
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
// the shutdown command received
private boolean shutdown = false; 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);
}
// Loop waiting for a request
while (!shutdown)
{
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try
{
//如果得到一个请求的话,就分别来建立一个输入流和输出流,然后分别建立一个请求和响应。
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream();
// create Request object and parse
Request request = new Request(input);
//控制台答应一下请求,然后解析出对应URL里面的请求路径
request.parse();
// create Response object
Response response = new Response(output);
response.setRequest(request);
//返回响应,发送数据
response.sendStaticResource();
// Close the socket
socket.close();
// check if the previous URI is a shutdown command
//控制这个循环什么时候结束
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
}
catch (Exception e)
{
e.printStackTrace();
continue;
}
}
}
}
package linkin;

import java.io.IOException;
import java.io.InputStream; public class Request
{
private InputStream input;
private String uri; public Request(InputStream input)
{
this.input = input;
} public String getUri()
{
return uri;
} //这里控制台打印一下请求的内容,方便我们查看
public void parse()
{
// Read a set of characters from the socket
StringBuffer request = new StringBuffer(2048);
byte[] buffer = new byte[2048];
int i;
try
{
i = input.read(buffer);
}
catch (IOException e)
{
e.printStackTrace();
i = -1;
}
for (int j = 0; j < i; j++)
{
request.append((char) buffer[j]);
}
System.out.print(request.toString());
uri = parseUri(request.toString());
} // 发过来的请求里面第一行是信息头,类似如下:GET /linkin.html HTTP/1.1
private String parseUri(String requestString)
{
//http://localhost:8080/SHUTDOWN
int index1, index2;
index1 = requestString.indexOf(' ');
if (index1 != -1)
{
index2 = requestString.indexOf(' ', index1 + 1);
if (index2 > index1)
//截取2个空格之间的内容,注意这里没有应用名了
return requestString.substring(index1 + 1, index2);
}
return null;
}
}
package linkin;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream; /**
* @author LinkinPark
* @Date 2015-3-11
*
*/
public class Response
{
private static final int BUFFER_SIZE = 1024;
Request request;//请求,主要是用请求URL里面的请求资源路径
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(HttpServer.WEB_ROOT, request.getUri());
if (file.exists())
{
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
{
// file not found
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 11Not Found</h1>";
output.write(errorMessage.getBytes());
}
}
catch (Exception e)
{
// thrown if cannot instantiate a File object
System.out.println(e.toString());
}
finally
{
if (fis != null)
fis.close();
}
}
}

ok,代码写完了,直接运行HttpServer的主方法启动服务器,现在要访问应用应该输入一个URL,前面代码也看到了,默认的目录就是在自己项目下面的webroot目录下,在这里我丢一个简单的HTML页面进去,用来访问:

<!DOCTYPE html>
<html>
<head>
<title>linkin.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> </head> <body>
愿有人陪你一起颠沛流离。。。<br>
</body>
</html>

输入URL:http://localhost:8080/linkin.html





输入URL:http://localhost:8080/SHUTDOWN   后台服务器停止了(因为服务器那段代码走完了,程序结束了)

自己模拟的一个简单的web服务器的更多相关文章

  1. 自己动手模拟开发一个简单的Web服务器

    开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的W ...

  2. 一个简单的web服务器

    写在前面 新的一年了,新的开始,打算重新看一遍asp.net本质论这本书,再重新认识一下,查漏补缺,认认真真的过一遍. 一个简单的web服务器 首先需要引入命名空间: System.Net,关于网络编 ...

  3. [置顶] 在Ubuntu下实现一个简单的Web服务器

    要求: 实现一个简单的Web服务器,当服务器启动时要读取配置文件的路径.如果浏览器请求的文件是可执行的则称为CGI程序,服务器并不是将这个文件发给浏览器,而是在服务器端执行这个程序,将它的标准输出发给 ...

  4. Tomcat剖析(一):一个简单的Web服务器

    Tomcat剖析(一):一个简单的Web服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三):连接器 ...

  5. 利用 nodeJS 搭建一个简单的Web服务器(转)

    下面的代码演示如何利用 nodeJS 搭建一个简单的Web服务器: 1. 文件 WebServer.js: //-------------------------------------------- ...

  6. 《深度解析Tomcat》 第一章 一个简单的Web服务器

    本章介绍Java Web服务器是如何运行的.从中可以知道Tomcat是如何工作的. 基于Java的Web服务器会使用java.net.Socket类和java.net.ServerSocket类这两个 ...

  7. 一个简单的Web服务器-支持Servlet请求

    上接 一个简单的Web服务器-支持静态资源请求,这个服务器可以处理静态资源的请求,那么如何处理Servlet请求的呢? 判断是否是Servlet请求 首先Web服务器需要判断当前请求是否是Servle ...

  8. 一个简单的Web服务器-支持静态资源请求

    目标 实现一个简单的Web服务器,能够根据HTTP请求的URL响应对应的静态资源,如果静态资源不存在则响应404. HttpServer 使用ServerSocket实现的一个服务器,request根 ...

  9. 如何用PHP/MySQL为 iOS App 写一个简单的web服务器(译) PART1

    原文:http://www.raywenderlich.com/2941/how-to-write-a-simple-phpmysql-web-service-for-an-ios-app 作为一个i ...

随机推荐

  1. [已解决]import pymssql ImportError: libsybdb.so.5

    在python3.6的环境下安装pymssql安装包,运行程序时报错:import pymssql ImportError: libsybdb.so.5 在网上搜索了一大圈很多都是讲文件存在但是没有添 ...

  2. Swagger文档转Word 文档

    GitHub 地址:https://github.com/JMCuixy/SwaggerToWord/tree/developer 原创作品,转载请注明出处:http://www.cnblogs.co ...

  3. 有关python下二维码识别用法及识别率对比分析

    最近项目中用到二维码图片识别,在python下二维码识别,目前主要有三个模块:zbar .zbarlight.zxing. 1.三个模块的用法: #-*-coding=utf-8-*- import ...

  4. 聚类之dbscan算法

    简要的说明: dbscan为一个密度聚类算法,无需指定聚类个数. python的简单实例: # coding:utf-8 from sklearn.cluster import DBSCAN impo ...

  5. 【三十三】thinkphp之SQL查询语句(全)

    一:字符串条件查询 //直接实例化Model $user=M('user1'); var_dump($user->where ('id=1 OR age=55')->select()); ...

  6. 把玩爬虫框架Gecco

    如果你现在接到一个任务,获取某某行业下的分类. 作为一个非该领域专家,没有深厚的运营经验功底,要提供一套摆的上台面且让人信服的行业分类,恐怕不那么简单. 找不到专家没有关系,我们可以爬虫.把那些专家的 ...

  7. 在虚拟机中安装metasploit官方攻防模拟器

    首先我们要在windwos下载安装perl环境.下载地址: http://pan.baidu.com/s/1i3GLKAp 然后我们安装 点击next 我同意,next next next,然后他会安 ...

  8. 51Nod 1277 字符串中的最大值(KMP,裸题)

    1277 字符串中的最大值 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 一个字符串的前缀是指包含该字符第一个字母的连续子串,例如: ...

  9. [bzoj1969] [Ahoi2005]LANE 航线规划

    tarjan.并查集.树状数组.树链剖分. 时间倒流,变删边为加边. 先求一波边双联通分量,缩点. 题目保证最后还是整张图联通的..所以就是一棵树. 现在的操作就是,将路径上的边权置0(加边时),查询 ...

  10. [bzoj3910] 火车

    一开始看错题了... 求经过的道路数量就求个lca,把路径上的点置为已经过的话,可以写一个并查集,把某个点往上连续已经过的一段点并起来. #include<cstdio> #include ...