自己模拟的一个简单的web服务器

首先我为大家推荐一本书: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   后台服务器停止了(因为服务器那段代码走完了,程序结束了)

时间: 2025-01-02 14:17:07

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

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

开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的Web服务器来体会一下. 一.请求-处理-响应模型 1.1 基本过程介绍 每一个HTTP请求都会经历三个步凑:请求-处理-响应:每当我们在浏览器中输入一个URL时都会被封装为一个HTTP请求报文发送到Web服务器,而Web服务器则接收并解析HTTP请求报文,然后针对请求进行处理(返回指定的HTML页面

使用 Nodejs 搭建一个简单的Web服务器

使用Nodejs搭建Web服务器是学习Node.js比较全面的入门教程,因为要完成一个简单的Web服务器,你需要学习Nodejs中几个比较重要的模块,比如:http协议模块.文件系统.url解析模块.路径解析模块.以及301重定向问题,下面我们就简单讲一下如何来搭建一个简单的Web服务器. 作为一个Web服务器应具备以下几个功能: 1.能显示以.html/.htm结尾的Web页面 2.能直接打开以.js/.css/.json/.text结尾的文件内容 3.显示图片资源 4.自动下载以.apk/.

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

原文:http://www.raywenderlich.com/2941/how-to-write-a-simple-phpmysql-web-service-for-an-ios-app 作为一个iPhone/iPad开发者,能够自己写一个简单的web服务器将是很有用的. 例如,你可能希望在软件启动时显示一些来自服务器的更新,或者在服务器端保存一些用户数据.除了你的想象力,没有什么能限制你了. 在第一篇中,我们将会一步一步的建立一个web服务器,基于promo code system(促销码系

一个简单的web服务器

static void Main(string[] args) { IPAddress localAddress = IPAddress.Loopback;//获取本机的ip地址 IPEndPoint endPoint =new IPEndPoint(localAddress, 49155); Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); socket.Bind

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

上接 一个简单的Web服务器-支持静态资源请求,这个服务器可以处理静态资源的请求,那么如何处理Servlet请求的呢? 判断是否是Servlet请求 首先Web服务器需要判断当前请求是否是Servlet请求. 像Tomcat,通过解析HTTP报文拿到请求url后,就可以根据web.xml来查找是否有匹配的Servlet,如果有匹配则认定为是一个有效的Servlet请求,然后将request,response传给对应的servlet的service()方法. 这里既然要实现一个简单的Web服务器,

(一)一个简单的Web服务器

万丈高楼平地起,首先我们必须了解 超文本传输协议(HTTP) 以后才能够比较清晰的明白web服务器是怎么回事. 1. 浅析Http协议 HTTP是一种协议,允许web服务器和浏览器通过互联网进行来发送和接受数据.它是一种请求和响应协议.客户端请求一个文件而服务器响应请求.HTTP使用可靠的TCP连接--TCP默认使用80端口.第一个HTTP版是HTTP/0.9,然后被HTTP/1.0所替代.正在取代HTTP/1.0的是当前版本HTTP/1.1,它定义于征求意见文档(RFC) 2616,可以从ht

学习用node.js建立一个简单的web服务器

一.建立简单的Web服务器涉及到Node.js的一些基本知识点: 1.请求模块 在Node.js中,系统提供了许多有用的模块(当然你也可以用JavaScript编写自己的模块,以后的章节我们将详细讲解),如http.url等.模块封装特定的功能,提供相应的方法或属性,要使用这些模块,需要先请求模块获得其操作对象. 例如要使用系统的http模块,可以这样写: var libHttp = require('http'); //请求HTTP协议模块 这样,以后的程序将可以通过变量libHttp访问ht

Tomcat学习笔记(一)一个简单的Web服务器

内容为<深入剖析Tomcat>第一章重点,以及自己的总结,如有描述不清的,可查看原书. 一.HTTP协议: 1.定义:用于服务器与客户端的通讯的协议,允许web服务器和浏览器通过互联网进行发送和接收数据.是一种请求和响应协议,使用可靠的TCP协议,TCP协议的端口为80,是一种面向连接的协议. 2.HTTP协议请求的三个组成部分:这三部分之间用回车换行符(CRLF)隔开 请求部分:方法(GET/POST等7种,其他的很少用,书上有介绍)[空格,该部分内容以空格隔开] 统一资源标识符URI[空格

java实现一个简单的Web服务器

Web服务器也称为超文本传输协议服务器,使用http与其客户端进行通信,基于java的web服务器会使用两个重要的类, java.net.Socket类和java.net.ServerSocket类,并基于发送http消息进行通信. 这个简单的Web服务器会有以下三个类: *HttpServer *Request *Response 应用程序的入口在HttpServer类中,main()方法创建一个HttpServer实例,然后调用其await()方法,顾名思义,await()方法会在指定端口