37.javaEE-手写web服务器

手写web服务器

总结:
1.所有的java的web服务器底层对象都是ServerSocket对象.
2.请求的对象都是流化对象.socket对象中解析出inputstream和outputstream,in转化成request对象,out转化成response对象.
3.线程池的代码的编写.

1.webServer类

步骤:
1.定义端口号,serverSocket,线程池等属性.
2.创建对象时调用init()方法,init()方法调用时,创建线程池.
3.start()方法,死循环接收socket,并且提交任务到线程池中.
4.service()方法,从socket中解析出inputstream和outputstream,并定义request对象和response对象.
将in和out转换成对应的request对象和response对象.
5.交给serviceDispatcher 对象分发,具体处理request对象和response对象.

**
 * 手写web服务器
 */
public class WebServer {
    /*
    定义服务器端口
     */
    private int port = 8888;

    /*
    web服务器
     */
    private ServerSocket serverSocket;

    /*
    线程池
     */
    private ThreadPoolExecutor threadPoolExecutor;

    /*
    构造方法
     */
    public WebServer() {
        init();
    }

    /*
    初始化web服务器
     */
    public void init(){
        try {
            serverSocket = new ServerSocket(this.port);
            threadPoolExecutor = new ThreadPoolExecutor(5,
                    10,
                    3, TimeUnit.SECONDS,
                    new ArrayBlockingQueue(20),
                    new ThreadPoolExecutor.DiscardPolicy()
            );
            System.out.println("服务器已经启动!!!");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /*
    启动web服务器,并且接收收到的socket,并且交由线程池处理
     */
    public  void start() throws IOException {
        while (true){
            final Socket accept = serverSocket.accept();
            threadPoolExecutor.submit(new Thread(){
                @Override
                public void run() {
                    service(accept);
                }
            });
        }
    }

    /*
    具体的业务
     */
    public void service(Socket socket){

        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
            System.out.println("接收到客户端的消息,客户端:" +socket.getInetAddress() +
                    ",端口号:" + socket.getPort());

            Request request  = new RequestParser().parse(inputStream);
            Response response = new Response(outputStream);
            service(request,response);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 交由dispatcher对象处理具体的request和response对象
     * @param request
     * @param response
     */
    private void service(Request request, Response response) {
        ServiceDispatcher serviceDispatcher = new ServiceDispatcher();
        serviceDispatcher.dispatcher(request,response);
    }

}

2.request对象
步骤:
1.request对象中包含了请求的全部东西,这里可以定义很多属性,比如url.请求方式,请求参数,等等.
2.将属性从inputstream中解析出来,分别赋值到各个属性中.

/**
 * 请求request
 */
public class Request {
    /*
    请求类型
     */
    private String type;

    /*
    请求的url
     */
    private String url;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getUrl() {
        return url;
    }

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

3.response对象
1.重构响应报文.
2.定义write方法,书写响应报文信息.

/**
 * 响应对象
 */
public class Response {
    private OutputStream output;

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

    /**
     * 输出文本信息
     * @param text
     * @throws IOException
     */
    public void writeText(String text) {
        FileInputStream fis = null;
        try {
            output.write("HTTP/1.1 200 OK\n".getBytes());
            output.write("Content-Type: text/html; charset=UTF-8\n\n".getBytes());
            output.write(text.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4.ServiceDispacher对象(请求转发对象)
步骤:
1.书写转发的方法,将接收到的参数request对象和response对象转发到具体的每一个servlet对象.

/**
 * 类似于springmvc中的dispatcherServlet
 */
public class ServiceDispatcher {

    public void dispatcher(Request request,Response response){
        executeController(request, response);
    }

    /**
     * 执行请求,并返回结果,这里主要是凭借相应头的方法
     * @param request
     * @param response
     */
    private void executeController(Request request, Response response) {
        String text = getControllerResult(request, response);
        StringBuilder sb = new StringBuilder();
        sb.append("请求类型: " + request.getType());
        sb.append("<br/>请求URI: " + request.getUrl());
        sb.append("<br/>返回结果: " + text);
        // 输出控制器返回结果
        System.out.println("响应:" + sb.toString());
        response.writeText(sb.toString());
    }

    /**
     * 模拟查找和执行控制器方法并返回结果,类似于将得到的request对象根据request的请求路径
     * 去controller层找相关的映射路径
     * @param request
     * @param response
     * @return
     */
    private String getControllerResult(Request request, Response response) {
        String text = "";
        String uri = request.getUrl();
        String [] uriArray = uri.split("\\/");
        if(uriArray.length != 3) {
            text = "请求路径没有找到相关匹配服务. ";
        } else if("test".equalsIgnoreCase(uriArray[1])) {
            TestController testController = new TestController();
            if("test1".equalsIgnoreCase(uriArray[2])) {
                text = testController.test1();
            } else if("test2".equalsIgnoreCase(uriArray[2])) {
                text = testController.test2();
            } else {
                text = "请求路径没有找到相关匹配服务. ";
            }
        } else {
            text = "请求路径没有找到相关匹配服务. ";
        }
        return text;
    }
}

5.requestParse解析器对象
步骤:
1.是将inputstream解析成request对象
2.读取inputstream中的信息.
3.解析请求方式.

/*
请求解析工具类,将inputStream解析成request对象
 */
public class RequestParser {
    private final static int BUFFER_SIZE = 1024;


    /*
    经inputStream解析程request请求
     */
    public Request parse(InputStream inputStream){
        Request request = new Request();
        //读取输入流中的信息
        String message = readMessage(inputStream);
        System.out.println("请求:" + message);
        //读取输入流中的type
        String type = parseType(message);
        request.setType(type);
        //读取输入流中的url
        String url = parseUri(message);
        request.setUrl(url);
        return request;
    }

    /*
    读取输入流中的信息
     */
    private String readMessage(InputStream inputStream) {
        //这是获取input中的信息
        StringBuffer readMessage = new StringBuffer();
        //这是每次读取的长度
        int readLength = 0;
        //
        byte[] buffer = new byte[BUFFER_SIZE];

        try {
            //读取的长度
            readLength = inputStream.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
            readLength = -1;
        }
        //读取完成之后,将读取的东西,添加到字符串缓冲区中
        for(int i = 0; i < readLength; i++) {
            readMessage.append((char) buffer[i]);
        }
        //返回字符串
        return readMessage.toString();
    }

    /**
     * 解析请求方式
     * @param requestString
     * @return
     */
    private String parseType(String requestString) {
        int index = 0;
        //从第一个空格开始截取
        index = requestString.indexOf(' ');
        if (index != -1) {
            return requestString.substring(0, index);
        }
        return null;
    }

    /**
     * 解析请求类型
     * @param requestString
     * @return
     */
    private String parseUri(String requestString) {
        int index1, index2;
        index1 = requestString.indexOf(' ');
        if (index1 != -1) {
            index2 = requestString.indexOf(' ', index1 + 1);
            if (index2 > index1)
                //返回第一个空格到第二个空格之间的
                return requestString.substring(index1 + 1, index2);
        }
        return null;
    }
}

**6.TestController对象,映射测试对象**
public class TestController {
    public String test1() {
        return "TestController.test1() 调用成功";
    }

    public String test2() {
        return "TestController.test2() 调用成功";
    }
}

7.TestMain主测试对象

public class TestMain {
    public static void main(String[] args) {
        try {
            new WebServer().start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

发布了42 篇原创文章 · 获赞 0 · 访问量 645

猜你喜欢

转载自blog.csdn.net/weixin_45449911/article/details/104639054