Java实现简易Tomcat服务器(内附原理和测试)

Tomcat简介

Tomcat服务器是一个轻量级的Java代码实现的Web服务器。这篇文章会讲述如何用Java实现一个简单的Tomcat服务器。

1.简易原理

  1. Tomcat开始运行后,会在服务器上开一个端口(本文中用的是8888端口),在所开辟的端口上运行一个ServerScoket,执行accpet()方法等待浏览器访问。
  2. 浏览器访问端口,ServerSocket的accept()方法返回一个运行在服务器端的socket,通过socket的getInputStream()方法和getOutputStream方法,可获得浏览器和服务器之间发送的内容和浏览器的响应内容()。
  3. 这里我们主要获取浏览器的请求地址和参数,响应时根据浏览器所传的参数和地址,到服务器上去寻找对应的资源(目前只支持静态资源),将用户请求的资源转化为文件流,传输给前端(浏览器)。
  4. 浏览器收到服务器的响应后,向用户展示界面。

2.实现类

主要分为以下几个类:
(1) Server 用于加载并启动服务器
(2) ServerThread 当接收到新请求时,开辟一个新的线程处理它
(3) Request 用于获取请求的数据(主要是请求的地址和请求参数)
(4) Response 用于响应请求(根据请求所获参数和地址,访问服务器上的资源)
(5) GetParam 用于获取环境变量参数

3.具体实现

package TomcatServer.server;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;

public class Server {

    private ServerSocket server;            //服务
    private int port;                       //端口号
    private static Properties prop;         //用于读取配置文件

    //配置参数读取位置
    static {
        prop = new Properties();
        try {
            prop.load(new FileInputStream(new File("src/TomcatServer/source/property.properties")));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }



    /*
     * @auther: Ragty
     * @describe: 初始化服务器
     * @param: []
     * @return: void
     * @date: 2019/1/24
     */
    public void init() {
        try {
            port = Integer.parseInt(prop.getProperty("port"));
            server = new ServerSocket(port);
            System.out.println("服务器启动"+ port + "端口");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /*
     * @auther: Ragty
     * @describe: 在当前线程内,创建一个Client服务
     * @param: []
     * @return: void
     * @date: 2019/1/25
     */
    public void recive() {
        try {
            System.out.println("收到新请求");
            Socket client = server.accept();                       //监听服务器,平时等待连接,有client则创建客户端实例(阻塞的)
            ServerThread thread = new ServerThread(client);        //处理客户端请求,并返回请求页面
            thread.start();
            thread.join();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public Server() {}


    /*
     * @auther: Ragty
     * @describe: 启动Tomcat服务器
     * @param: [args]
     * @return: void
     * @date: 2019/1/25
     */
    public static void main(String[] args) {
        Server server2 = new Server();
        server2.init();
        while (true) {           //一直等待用户访问定义端口,访问后,开辟新线程处理它
            server2.recive();
        }
    }

}

package TomcatServer.Request;

import TomcatServer.Util.GetParam;
import com.hjy.util.GetParm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class Request {
    private Socket client;                  //客户端
    private BufferedReader reader;
    private String url;                     //请求资源
    private String method;                  //请求方式
    private String protocal;                //请求协议
    private Map<String,String> map;         //参数列表
    private GetParam getParam;              //请求参数分割工具


    public Request() {}

    /*
     * @auther: Ragty
     * @describe: 接收并客户端(Client)发出的请求,获取请求的链接及参数
     * @param: [client]
     * @return:
     * @date: 2019/1/25
     */
    public Request(Socket client) {
        this.client = client;
        map = new HashMap<>();
        getParam = new GetParam();
        try {
            reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
            String firstLine = reader.readLine();
            String[] spilt = firstLine.split(" ");

            method = spilt[0];
            url = spilt[1];
            protocal = spilt[2];
            System.out.println(url);

            if (method.equalsIgnoreCase("get")) {
                if(url.contains("?")) {
                    String[] split2 = url.split("[?]");
                    url = split2[0];                               //重新定义url
                    String property = split2[1];
                    map = getParam.getParam(property);             //分割参数
                 }
            } else {
                int length = 0;
                while (reader.ready()) {                           //确保已经缓冲完毕
                    String line = reader.readLine();
                    if (line.contains("Content-Length")) {
                        String[] spilt2 = line.split(" ");
                        length = Integer.parseInt(spilt2[1]);
                    }
                    if (line.equals("")) {                          //Post方法无参数
                        break;
                    }
                }
                String info = null;
                char[] ch = new char[length];
                reader.read(ch , 0, length);
                info = new String(ch, 0, length);
                map = getParam.getParam(info);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    public Socket getClient() { return client; }
    public void setClient(Socket client) { this.client = client; }

    public String getUrl() { return url; }
    public void setUrl(String url) { this.url = url; }

    public String getMethod() { return method; }
    public void setMethod(String method) { this.method = method; }

    public String getProtocal() { return protocal; }
    public void setProtocal(String protocal) { this.protocal = protocal; }

}

package TomcatServer.Response;

import java.io.*;
import java.net.Socket;

public class Response {

    private Socket client;
    private PrintStream ps;
    private String path = null;

    public Response() {};

    /*
     * @auther: Ragty
     * @describe: 获取服务端传输给客户端的输出流
     * @param: [client]
     * @return:
     * @date: 2019/1/24
     */
    public Response(Socket client) {
        super();
        this.client = client;
        try {
            ps = new PrintStream(client.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    /*
     * @auther: Ragty
     * @describe:根据当前路径将服务器上有的资源用流传给客户端
     * @param: []
     * @return: void
     * @date: 2019/1/24
     */
    public void forword() throws FileNotFoundException {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(new File(path));
            ps.println("HTTP/1.1 200 OK");
            ps.println();
            byte[] buf = new byte[1024];
            int length = 0;
            while ( (length = fis.read(buf)) != -1 ) {
                ps.write(buf, 0, length);
                ps.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) {fis.close();}
                if (ps != null) {ps.close();}
                if (client != null) {client.close();}
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }



    /*
     * @auther: Ragty
     * @describe: 分情况处理请求Url(1.为空,返回默认资源 2.存在,加载该资源 3.不存在,返回错误信息)
     * @param: [url]
     * @return: void
     * @date: 2019/1/24
     */
    public void forword(String url) {

        if (url.equals("/")) {
            path = "src/TomcatServer/source/2.jpg";
        } else {
            path = "src/TomcatServer/source" + url;
            File file = new File(path);
            if (!file.exists()) { path = "src/TomcatServer/source/error.html"; }
        }

        try {
            forword();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

}

4.测试效果

浏览器输入 http://localhost:8888 ,效果如下

浏览器输入 http://localhost:8888/success.html ,效果如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值