创建一个简单的web服务器

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





相关文章
|
17小时前
|
网络协议 数据格式 Python
Python进阶---HTTP协议和Web服务器
Python进阶---HTTP协议和Web服务器
15 4
|
18小时前
|
弹性计算 关系型数据库 MySQL
【阿里云弹性计算】从零搭建:基于阿里云ECS的高性能Web服务部署实践
【5月更文挑战第21天】本文介绍了如何使用阿里云ECS搭建高性能Web服务。首先,注册阿里云账号购买ECS实例,选择合适配置。接着,通过SSH连接实例,更新系统并安装Apache、PHP和MySQL。创建网站目录,上传代码,配置数据库和PHP。然后,启用Gzip压缩和KeepAlive,调整Apache并发连接数以优化性能。此教程为在阿里云上构建高效Web服务提供了基础指南。
19 5
|
4天前
|
JavaScript 前端开发 Java
web服务器是什么
web服务器是什么
18 0
|
5天前
|
应用服务中间件 网络安全 Apache
构建高性能Web服务器:Nginx vs Apache
【5月更文挑战第16天】Nginx与Apache是两种主流Web服务器,各具优势。Nginx以其轻量级、高并发处理能力和反向代理功能见长,适合大型网站和高并发场景;而Apache以功能丰富、稳定性强闻名,适合企业网站和需要多种Web服务功能的场景。在性能上,Nginx处理高并发更优,Apache则可能在高负载时遭遇瓶颈。在选择时,应根据实际需求权衡。
|
6天前
|
JSON JavaScript API
使用 Node.js 开发一个简单的 web 服务器响应 HTTP post 请求
使用 Node.js 开发一个简单的 web 服务器响应 HTTP post 请求
19 1
|
6天前
|
JSON JavaScript 中间件
使用 Node.js 开发一个简单的 web 服务器响应 HTTP get 请求
使用 Node.js 开发一个简单的 web 服务器响应 HTTP get 请求
10 2
|
6天前
|
负载均衡 Go 调度
使用Go语言构建高性能的Web服务器:协程与Channel的深度解析
在追求高性能Web服务的今天,Go语言以其强大的并发性能和简洁的语法赢得了开发者的青睐。本文将深入探讨Go语言在构建高性能Web服务器方面的应用,特别是协程(goroutine)和通道(channel)这两个核心概念。我们将通过示例代码,展示如何利用协程处理并发请求,并通过通道实现协程间的通信和同步,从而构建出高效、稳定的Web服务器。
|
6天前
【计网·湖科大·思科】实验一 熟悉仿真软件及访问WEB服务器
【计网·湖科大·思科】实验一 熟悉仿真软件及访问WEB服务器
7 0
|
6天前
|
存储 安全 数据安全/隐私保护
Web应用程序的会话管理是一种跟踪和识别特定用户与Web服务器之间交互的技术
【5月更文挑战第12天】Python Web开发中,会话管理用于跟踪用户与服务器交互,如Flask框架提供的内置功能。以下是一个简单示例:安装Flask后,设置应用密钥,通过session读写用户状态。例如,创建一个显示和设置用户名称的Web应用,用户提交的名字将保存在会话中。在生产环境中,应安全存储密钥,如使用环境变量。扩展会话管理可借助第三方库实现更多功能,但可能需更多配置。
215 2

热门文章

最新文章