创建一个简单的web服务器

Web服务器也称为超文本传输协议(HTTP)服务器,因为它使用HTTP来跟客户端进行通信的。既然说到通信那就离不了Java里的两个重要的类java.net.Socket和java.net.ServerSocket。这里浏览器一方可以认为是一个客户端,接收HTTP请求的一方可以认为是服务端。在这之前我们先说一下HTTP协议。

HTTP协议允许web服务器和浏览器通过网络来进行发送和接收数据。它是一种请求和响应协议。客户端发送一个请求,服务端响应这个请求。HTTP请求由三部分组成,分别是:请求行、消息报头(请求头)、请求正文(一般是POST请求)。注意:请求头和请求正文中间有一个空行。一个请求行以一个方法开头,一个空格隔开,后面跟着请求的URI和协议的版本。格式如下Method Request-URI HTTP-Version CRLF。其中Method表示请求方法,Request-URI是一个统一资源标识符,HTTP-Version表示请求的HTTP协议版本,CRLF表示回车和换行(除了作为结尾的CRLF之外,不允许出现单独的CR或LF字符)HTTP响应也是由三个部分组成,分别是:状态行、消息报头(响应头)、响应正文。响应头和响应正文中间有一个空行。状态行的格式如下:HTTP-Version
Status-Code Reason-Phrase CRLF。其中,HTTP-Version表示服务器HTTP协议的版本,Status-Code表示服务器发回的响应状态码,Reason-phrase表示状态代码的文本描述。说了这么多可能你看的还是有点晕,通过下面这张图你应该能看得更清楚一点:

OK,我们上面说了浏览器可以当做是一个客户端,那么我们只需要写一个服务端就行了。下面的代码只是简单的模拟了请求静态资源和处理一个简单的Servlet。

服务端代码如下:

package com.zkn.imitate.tomcat.secondchapter.first;

import com.zkn.imitate.tomcat.secondchapter.Request;
import com.zkn.imitate.tomcat.secondchapter.Response;
import com.zkn.imitate.tomcat.secondchapter.StaticResourceProcessor;
import com.zkn.imitate.tomcat.utils.Constants;
import com.zkn.imitate.tomcat.utils.StringUtil;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by wb-zhangkenan on 2016/12/29.
 */
public class HttpServer {

    public static void main(String[] args){

        await();
    }

    private static void await() {

        ServerSocket serverSocket = null;
        try {
            boolean shutDown = false;
            //创建一个服务端
            serverSocket = new ServerSocket(8004,1, InetAddress.getByName("127.0.0.1"));
            while (!shutDown){
                //接收客户端请求
                Socket socket = serverSocket.accept();
                Request request = new Request(socket.getInputStream());
                request.parseRequest();//解析请求信息
                Response response = new Response(socket.getOutputStream());
                String uri = request.getUri();
                if(uri !=null && uri.startsWith("/favicon.ico")){

                }else if(!StringUtil.isEmpty(uri) && uri.startsWith("/static/")){
                    StaticResourceProcessor resouce = new StaticResourceProcessor();
                    resouce.process(request,response);//处理静态资源
                }else{
                    ServletProcessor servletProcessor = new ServletProcessor();
                    servletProcessor.process(request,response);//处理Servlet
                }
                socket.close();
                shutDown = Constants.SHUT_DOWN.equals(request.getUri());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

模拟的Request主要代码如下:

public class Request implements ServletRequest {
    /**
     * 输入流
     */
    private InputStream inputStream;
    /**
     * uri
     */
    private String uri;

    public Request(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    public void parseRequest(){

        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        StringBuffer sb = new StringBuffer();
        String str = null;
        try {
            while((str = br.readLine()) != null){
                if("".equals(str))
                    break;
                sb.append(str).append("\n");
            }
            System.out.println(sb.toString());
            uri = StringUtil.parserUri(sb.toString()," ");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

模拟的Response主要代码如下:

public class Response implements ServletResponse {
    /**
     * 输出流
     */
    private OutputStream outputStream;
    /**
     * 字符输出流
     */
    private PrintWriter printWriter;

    public Response(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    public void sendStaticResource(String path) {

        FileInputStream fis = null;
        try {
            File file = new File(Constants.WEB_PATH, path);
            if (file.exists() && !file.isDirectory()) {
                if (file.canRead()) {
                    fis = new FileInputStream(file);
                    int flag = 0;
                    byte[] bytes = new byte[1024];
                    while ((flag = fis.read(bytes)) != -1){
                        outputStream.write(bytes);
                    }
                }
            }else{
                PrintWriter printWriter = getWriter();
                //这里用PrintWriter字符输出流,设置自动刷新
                printWriter.write("HTTP/1.1 404 File Not Found \r\n");
                printWriter.write("Content-Type: text/html\r\n");
                printWriter.write("Content-Length: 23\r\n");
                printWriter.write("\r\n");
                printWriter.write("<h1>File Not Found</h1>");
                printWriter.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fis != null)
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

静态资源处理类:

public class StaticResourceProcessor {

    public void process(Request request,Response response){

        response.sendStaticResource(request.getUri());
    }
}

Servlet处理类如下:

public class FirstServlet implements Servlet{

    public void init(ServletConfig servletConfig) throws ServletException {

    }

    public ServletConfig getServletConfig() {
        return null;
    }

    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

        PrintWriter out = servletResponse.getWriter();
        out.println("Hello. Roses are red.");
    }

    public String getServletInfo() {
        return null;
    }

    public void destroy() {

    }
}

ServletProcessor的代码如下:

package com.zkn.imitate.tomcat.secondchapter.first;

import com.zkn.imitate.tomcat.secondchapter.Request;
import com.zkn.imitate.tomcat.secondchapter.Response;
import com.zkn.imitate.tomcat.utils.Constants;
import com.zkn.imitate.tomcat.utils.StringUtil;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;

/**
 * Created by wb-zhangkenan on 2016/12/29.
 */
public class ServletProcessor {
    /**
     * 处理请求信息
     * @param request
     * @param response
     */
    public void process(Request request, Response response){

        String str = request.getUri();
        String servletName = null;
        if(!StringUtil.isEmpty(str) && str.lastIndexOf("/") >= 0){
            servletName = str.substring(str.lastIndexOf("/")+1);
        }
        URLClassLoader classLoader = null;
        URL[] url = new URL[1];

        URLStreamHandler streamHandler = null;
        File classPath = new File(Constants.WEB_ROOT);

        try {
            //创建仓库
            String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
            url[0] = new URL(null,repository,streamHandler);
            classLoader = new URLClassLoader(url);//URL类加载器

            Class clazz = classLoader.loadClass(servletName);
            Servlet servlet = (Servlet) clazz.newInstance();
            servlet.service(request,response);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ServletException e) {
            e.printStackTrace();
        }
    }
}

下面我们看一下请求结果如何:

当我们输入:http://localhost:8004/FirstServlet时,请求结果如下所示:

当我们输入:http://localhost:8004/static/image01.jpg时,请求结果如下所示:


从上面的结果可以看到,我们做的简单的web服务器可以正常工作了。当然了这个只是最简单的web服务器了,以后我会把这个写的完整一些强大一些。完整的代码请从这里下载:https://github.com/zhangconan/ImitateTomCat

时间: 2024-08-07 03:20:20

创建一个简单的web服务器的相关文章

创建一个简单的web服务器(二):使用自定义的类加载器来替换URLClassLoader

在上一章中我们加载Servlet用的是URLClassLoader,在这一章中我们使用自定义的类加载器来替换URLClassLoader.关于类加载器的文章请参考这里:深入探讨 Java 类加载器.这篇文章写得很棒. 具体的代码如下: package com.zkn.imitate.tomcat.secondchapter.first; import com.zkn.imitate.tomcat.secondchapter.Request; import com.zkn.imitate.tomc

一个简单的web服务器

写在前面 新的一年了,新的开始,打算重新看一遍asp.net本质论这本书,再重新认识一下,查漏补缺,认认真真的过一遍. 一个简单的web服务器 首先需要引入命名空间: System.Net,关于网络编程的大部分类型及操作都可以在这个命名空间下找到. IPAddress:类用来表示一个ip地址. IPEndPoint:用来表示一个IP地址和一个端口号的组合,称为网络的端点. System.Net.Sockets:命名空间中提供了基于Socket编程的数据类型. Socket类封装了Socket的操

使用 CodeIgniter 创建一个简单的 Web 站点

原文:使用 CodeIgniter 创建一个简单的 Web 站点   参考源自: http://www.ibm.com/developerworks/cn/web/wa-codeigniter/index.html 我的第一个 CodeIgniter 项目(除HelloWorld外),现整理记录下来.   相关环境: 系统:ubuntu-10.04.3 Apache:httpd-2.4.7 PHP:php-5.4.22 MySQL:mysql-5.6.16 CI:CodeIgniter-2.2.

SharePoint中创建一个简单的Web Part 部件

标准的Web部件有时候可以非常强大,可以执行许多函数.本文主要讲解如何使用Visual Studio 创建一个简单的Web部件. 1. 打开VS,点击文件----新建项目. 2. 选择空白SharePoint项目.命名SmallvilleWebPartProject,点击确定.选择部署为场解决方案. 3. 右击项目添加新项目. 4. 选择Web部件. 5. 命名CustomerInformation,点击添加. 6. 右击新的Web部件项目,选择添加类,命名CustomerData,点击确定.

《深入剖析Tomcat》一第 1 章 一个简单的Web服务器

第 1 章 一个简单的Web服务器 本章介绍Java Web服务器是如何运行的.Web服务器也称为超文本传输协议(HyperText Transfer Protocol,HTTP)服务器,因为它使用HTTP与其客户端(通常是Web浏览器)进行通信.基于Java的Web服务器会使用两个重要的类:java.net.Socket类和java.net.ServerSocket类,并通过发送HTTP消息进行通信.本章先介绍HTTP协议和这两个类,然后介绍一个简单的Web服务器.

如何用node.js实现一个简单的web服务器

node.js实现web服务器还是比较简单的,我了解node.js是从<node入门>开始的,如果你不了解node.js也可以看看! 我根据那书一步一步的练习完了,也的确大概了解了node.js,不过里面写的路由的地方总感觉不方便,十一放假最后一天,试着写了个简单的web服务器,现在分享记录于此! http模块已提供了基本功能,所以我主要解决两个问题,1是静态资源的处理,2是动态资源的路由. 静态资源在node.js里的意思是不变的,如图片.前端js.css.html页面等. 动态资源我们一般

通过ASP.NET Web API + JQuery创建一个简单的Web应用

看了dudu的<HttpClient + ASP.NET Web API, WCF之外的另一个选择>一文,想起多很久之前体现ASP.NET Web API而创建的一个Demo.这是一个只涉及到简单CRUD操作的Web应用,业务逻辑以Web API的形式定义并以服务的形式发布出来,前台通过jQuery处理用户交互并调用后台服务. 一.一个简单的基于CRUD的Web应用 这个简单的Demo应用用于模拟"联系人管理".当页面加载的时候,所有的联系人列表被列出来.在同一个页面中,我

[JAVA100例]050、一个简单的Web服务器

import java.io.*; import java.net.*; /** * <p>Title: 发现HTTP内容和文件内容</p> * <p>Description: 获得用户请求后将用户需要的文件读出,添加上HTTP应答头.发送给客户端.</p> * <p>Copyright: Copyright (c) 2003</p> * <p>Filename: Response.java</p> * @ve

go 语言实现一个简单的 web 服务器

学习Go语言的一些感受,不一定准确. 假如发生战争,JAVA一般都是充当航母战斗群的角色.一旦出动,就是护卫舰.巡洋舰.航母舰载机.预警机.电子战飞机.潜艇等等浩浩荡荡,杀将过去.(JVM,数十个JAR包,Tomcat中间件,SSH框架,各种配置文件...天生就是重量级的,专为大规模作战) 而GO语言更像F35战斗轰炸机单枪匹马,悄无声息,投下炸弹然后走人.专属轰炸机,空战也会一点点.实在搞不定,就叫它大哥F22.(GO是编译型语言,不需要依赖,不需要虚拟机,可以调用C代码并且它足够简单,却非常