通过线程池实现一个简单的Web服务器

测试步骤:

  • 执行HttpServerMain.java
  • 浏览器访问http://127.0.0.1:8181/test.html

SimpleHttpServer.java

该类定义了对端口的监听,对每一个请求的具体处理,和开启服务器。

package com.httpServerTest;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

import com.threadpooltest.DefaultThreadPool;
import com.threadpooltest.ThreadPool;

public class SimpleHttpServer {
    //处理HttpRequest的线程池
    static ThreadPool<HttpRequestHandler> threadPool = new DefaultThreadPool<HttpRequestHandler>(1);
    static String basePath;
    static ServerSocket serverSocket;
    //服务监听端口
    static int port = 8181;
    
    public static void setPort(int port){
        if(port>0){
            SimpleHttpServer.port = port;
        }
    }
    public static void setBasePath(String basePath){
        if(basePath != null && new File(basePath).exists() && new File(basePath).isDirectory()){
            SimpleHttpServer.basePath = basePath;
        }
    }
    //启动SimpleHttpServer
    public static void start() throws Exception{
        serverSocket = new ServerSocket(port);
        Socket socket = null;
        while((socket=serverSocket.accept()) != null){
            //接收一个客户端Socket,生成一个HttpRequestHandler,放入线程池中执行
            threadPool.execute(new HttpRequestHandler(socket));
        }
        serverSocket.close();
    }
    
    static class HttpRequestHandler implements Runnable{
        private Socket socket;
        public HttpRequestHandler(Socket socket) {
            this.socket = socket;
        }
        @Override
        public void run() {
            String line = null;
            BufferedReader br = null;
            BufferedReader reader = null;//读socket的输入
            PrintWriter out = null;//读socket的输出
            InputStream in = null;//读图片文件
            try{
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String header = reader.readLine();
                System.out.println("收到header=" + header);
                //由相对路径计算出绝对路径
                String filePath = basePath + header.split(" ")[1];
                out = new PrintWriter(socket.getOutputStream());
                if(! new File(filePath).exists()){
                    out.flush();
                    return;
                }
                //如果有请求资源的后缀是.jpg或者.ico,则读取资源并输出
                if(filePath.endsWith(".jpg")){
                    in = new FileInputStream(filePath);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    int i = 0;
                    while((i = in.read()) != -1){
                        baos.write(i);
                    }
                    byte[] array = baos.toByteArray();
                    out.println("HTTP/1.1 200 OK");
                    out.println("Server: Molly");
                    out.println("Content-Type:image/jpeg");
                    out.println("Content-Length:" + array.length);
                    out.println("");
                    socket.getOutputStream().write(array, 0, array.length);
                }else{
                    br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
                    out.println("HTTP/1.1 200 OK");
                    out.println("Server: Molly");
                    out.println("Content-Type:text/html;charset=UTF-8");
                    out.println("");
                    while((line = br.readLine()) != null){
                        out.println(line);
                    }
                }
                out.flush();
            }catch(Exception e){
                e.printStackTrace();
                out.println("HTTP/1.1 500");
                out.println("");
                out.flush();
            }finally{
                close(br, in, reader, out, socket);
            }
        }
        //关闭流或者socket
        private static void close(Closeable... closeables){
            if(closeables != null){
                for(Closeable closeable : closeables){
                    try {
                        if(closeable!=null){
                            closeable.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }           
            }
        }
    }
}

HttpServerMain.java

package com.httpServerTest;

public class HttpServerMain {

    public static void main(String[] args) {
        SimpleHttpServer shs = new SimpleHttpServer();
        shs.setBasePath("D:/testDir"); //将根目录定义到html所在的目录
        try {
            shs.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

一个简易的html页面test.html

将该页面和任意三个命名为1.jpg/2.jpg/3.jpg的图片放到d:\testDir文件夹。

<html>
    <head>
        <title>测试页面</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    </head>
    <body align="center">
        <h1>第一张图片</h1>
        <img src="1.jpg" alt="" align="middle"/>
        <h1>第二张图片</h1>
        <img src="2.jpg" alt="" align="middle"/>
        <h1>第三张图片</h1>
        <img src="3.jpg" alt="" align="middle"/>
    </body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,869评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,754评论 18 399
  • 1 Redis介绍1.1 什么是NoSql为了解决高并发、高可扩展、高可用、大数据存储问题而产生的数据库解决方...
    克鲁德李阅读 5,354评论 0 36
  • 我盼望着一场火山的爆发 我等待着一场海啸的颤栗 如果痛苦能让人放弃思考 我愿重生十次 再重生十次 我将行走在黑暗里...
    小木土水阅读 180评论 0 2
  • 我似乎尝试了很多,想讲好英文又没有在一件事或者说一个方向坚持下来过。对,我确实不想仅仅因为考四六级,考研去学习英文...
    追咪阅读 617评论 19 1