手写一个简单的web服务器

十年热恋 提交于 2020-02-25 22:38:35
// 定义两个注解类
public @interface Controller {
    String value() default "";
}

public @interface GetMapping {
    String value() default  "";
}

// 标注controller对象
@Controller
public class IndexController {

	// 自定义注解
    @GetMapping("/index")
    public String index(String name){
        return "Welcome " + name;
    }
}

// 封装了资源类
public class Request {
    private Class[] parameterTypes;
    private Object returnType;
    private Method method;
    private Class clazz;
}

// 暴露一个端口,并且解析所有的controller
public class Server {
    private int port = 8080;
    private static final Map<String, Request> GET_MAPPING = new HashMap<>();
    private static String bashScanPackage = "com.data.controller";
    private ClassLoader classLoader = Server.class.getClassLoader();
    private ServerSocket socket;

    /**
     * 初始化
     *
     * @throws ClassNotFoundException
     */
    private void init() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        URL url = classLoader.getResource(bashScanPackage.replaceAll("\\.", "/"));
        String filePath = url.getFile();
        File file = new File(filePath);
        for (String s : file.list()) {
            s = s.substring(0, s.indexOf("."));
            Class clazz = Class.forName(bashScanPackage + "." + s);
            if (!clazz.isAnnotationPresent(Controller.class)) {
                continue;
            }
            Method[] methods = clazz.getDeclaredMethods();
            for (Method m : methods) {
                GetMapping getMapping = m.getAnnotation(GetMapping.class);
                if (getMapping == null) {
                    continue;
                }

                Request req = new Request();
                req.setMethod(m);
                req.setClazz(clazz);
                req.setParameterTypes(m.getParameterTypes());
                req.setReturnType(m.getReturnType());
                GET_MAPPING.put(getMapping.value(), req);
            }

        }
    }

    private void start() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        init();

        socket = new ServerSocket(port);
        System.out.println("server startup, current port:" + port);
        while (true) {
            Socket client = socket.accept();
            processor(client);
        }

    }

    private void processor(Socket client) throws IOException {
        InputStream is = client.getInputStream();
        OutputStream os = client.getOutputStream();
        String[] res = requestProcessor(is);
        if (res == null || res.length < 3) {
            responseProcessor(os, "403", "Request Bad!", "");
            destroy(client, is, os);
            return;
        }
        String method = res[0];
        String url = res[1];
        String protocol = res[2];
        System.out.println(protocol + "::" + method + "::" + url);

        if (!GET_MAPPING.containsKey(url)) {
            responseProcessor(os, "404", "404-Not Found!", "");
            destroy(client, is, os);
            return;
        }
        Request request = GET_MAPPING.get(url);
        Object o;
        try {
            o = request.getMethod().invoke(request.getClazz().newInstance(), "lisa");
            responseProcessor(os, "200", "OK", o.toString());
        } catch (Exception e) {
            e.printStackTrace();
            responseProcessor(os, "501", "Server unavailable!", "");
        } finally {
            destroy(client, is, os);
        }
    }

    private void destroy(Socket client, InputStream is, OutputStream os) throws IOException {
        os.flush();
        os.close();
        is.close();
        client.close();
    }

    private void responseProcessor(OutputStream outputStream, String code, String desc, String data) throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.1")
                .append(code + "\t")
                .append(desc + "\n")
                .append("Content-Type: text/html;\n")
                .append("\r\n")
                .append(data);
        outputStream.write(sb.toString().getBytes());
    }

    private String[] requestProcessor(InputStream inputStream) throws IOException {
        try {
            //拿到HTTP协议内容
            String content = "";
            byte[] buff = new byte[1024];
            int len;
            if ((len = inputStream.read(buff)) != -1) {
                content = new String(buff, 0, len);
            }

            String line = content.split("\\n")[0];
            return line.split("\\s");

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }


    public static void main(String[] args) throws Exception {
        Server server = new Server();
        server.start();
    }

基于netty的改造

 <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.25.Final</version>
        </dependency>
private void start() throws Exception {
        init();
        // Boss线程
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // Worker线程
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // Netty服务
            ServerBootstrap server = new ServerBootstrap();
            server.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        // 客户端初始化处理
                        protected void initChannel(SocketChannel client) {
                            client.pipeline().addLast(new HttpResponseEncoder());
                            client.pipeline().addLast(new HttpRequestDecoder());
                            // 业务逻辑处理
                            client.pipeline().addLast(new WebServerHandler(GET_MAPPING));
                        }
                    }                
                    .option(ChannelOption.SO_BACKLOG, 10)
                    // 针对子线程的配置 保持长连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // 启动服务器
            ChannelFuture f = server.bind(port).sync();
            System.out.println("server startup, listener port:" + port);
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

	//业务处理							  
								  public class WebServerHandler extends ChannelInboundHandlerAdapter {
    private ChannelHandlerContext channelHandlerContext;
    private HttpRequest request;
    private Map<String, Request> GET_MAPPING;

    public WebServerHandler(Map<String, Request> GET_MAPPING) {
        this.GET_MAPPING = GET_MAPPING;
    }

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpRequest) {
            channelHandlerContext = ctx;
            request = (HttpRequest) msg;
            String url = request.uri();
            int len = request.uri().indexOf("?");
            if (len != -1) {
                url = request.uri().substring(0, len);
            }
            if (!GET_MAPPING.containsKey(url)) {
                responseProcessor("404-Not Found!");
                return;
            }
            Request source = GET_MAPPING.get(url);
            Object obj = source.getMethod().invoke(source.getClazz().newInstance(), null);
            responseProcessor((String) obj);
        }
    }

    private void responseProcessor(String data) throws UnsupportedEncodingException {
        FullHttpResponse resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                Unpooled.wrappedBuffer(data.getBytes("UTF-8")));
        resp.headers().set("Content-Type", "text/html;");
        channelHandlerContext.write(resp);
        channelHandlerContext.flush();
        channelHandlerContext.close();

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!