基于ServerSocket模拟web容器

基于ServerSocket模拟web容器_第1张图片
80608141210.png

最近工作经常会遇到要做一个很小的微服务,对并发要求不高,尽量小,要提供
api,还要查数据库。想想使用Spingboot,tomcat,Mybatis能妥妥的解决,可是还是太
大了,业界还有很多例如Weblogic,jetty,Lighttpd等等,都是企业级的应用。思来想
去,估计需要自己做一个实现http协议的web服务器了;

思路大概如下:
1.new一个ServerSocket,监听某个端口
2.socket等待新的请求接入
3.当有新的请求接入,直接new一个任务提交给线程池处理
4.SocketHandler主要处理请求,获取请求参数,并根据对应的请求规则路由到对应的处理

1.主程序

package com.example.demo.server.serverSocket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TCPServer {

    public ExecutorService executorService= Executors.newFixedThreadPool(200);

    public void start() {
        try {
            ServerSocket serverSocket= new ServerSocket(8090);
            System.out.println("ServerSocket监听端口:"+serverSocket.getLocalPort());
            while (true){
                Socket socket= serverSocket.accept();
                System.out.println("request客户的地址为:"+socket.getInetAddress()+":"+socket.getPort());
                try {
                    executorService.execute(new SocketHandler(socket));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

2.处理类

package com.example.demo.server.serverSocket;

import com.alibaba.fastjson.JSON;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class SocketHandler implements Runnable {

    private Socket socket;

    public SocketHandler(Socket socket){
        this.socket= socket;
    }

    @Override
    public void run() {
        try {
            socketHandler(socket);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void socketHandler(Socket socket) throws IOException, InterruptedException {
        //1.获取请求
        InputStream inputStream = socket.getInputStream();
        Thread.sleep(10);
        int len= inputStream.available();
        byte[] bytes= new byte[len];
        inputStream.read(bytes);
        String request= new String(bytes);
        System.out.println(request);
        //2.处理请求并回掉
        callBack(request,socket.getOutputStream());
    }

    private Map requestParameters(String request){
        Map map= new HashMap<>();
        String path= null;
        try {
            String[] lines= request.split("\r\n");
            for(int i=0;i-1){
                    Map body= null;
                    try{
                        body= JSON.parseObject(trim(line),HashMap.class);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    map.put("reqBody", body);
                }else {
                    String[] parts= line.split(":");
                    if(parts.length>1){
                        map.put(trim(parts[0]),trim(parts[1]));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    private String trim(String s){
        if(s!=null){
            return s.trim().replaceAll("\r\n","");
        }
        return "";
    }

    private void callBack(String request,OutputStream outputStream){
        String firstLine= request.substring(0,request.indexOf("\r\n"));
        String[] parts= firstLine.split(" ");
        String path= parts[1];
        //1.请求数据,规定必须以.json为结尾,也可以自定义格式,这里只是举例
        if(path.indexOf(".json")>-1){
            toData(path,outputStream,request);
        }else{//2.请求页面
            toView(path,outputStream);
        }
    }

    //1.请求数据
    private void toData(String path,OutputStream outputStream,String request){
        //组装请求参数
        Map params= requestParameters(request);
        System.out.println(JSON.toJSON(params));
        PathRouter.router(path,outputStream);
    }

    //2.请求页面或者静态文件
    private void toView(String path,OutputStream outputStream){
        InputStream in= TCPServer.class.getResourceAsStream(path);
        String contentType= getContentType(path);
        String responseFirstLine= "HTTP/1.1 200 OK\r\n";
        String responseHeader="Content-type:"+contentType+"\r\n\r\n";
        if(in==null){
            responseFirstLine= "HTTP/1.1 404 OK\r\n";
        }
        try {
            outputStream.write(responseFirstLine.getBytes());
            outputStream.write(responseHeader.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            int length=0;
            byte[] bytes= new byte[128];
            while ((length=in.read(bytes))!=-1){
                outputStream.write(bytes,0,length);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getContentType(String uri) {
        if(uri.indexOf("html")!=-1||uri.indexOf("htm")!=-1)
            return  ContentType.html;
        else if(uri.indexOf("jpg")!=-1||uri.indexOf("jpeg")!=-1)
            return ContentType.jpg;
        else if(uri.indexOf("gif")!=-1)
            return ContentType.gif;
        else if(uri.indexOf("png")!=-1){
            return ContentType.png;
        }
        return ContentType.octetStream;
    }
}

3.路由Router

package com.example.demo.server.serverSocket;

import com.alibaba.fastjson.JSON;
import com.sun.xml.internal.bind.v2.TODO;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 类似于dispatcher功能实现路径转发
 * 不过在此过于简单
 */
public class PathRouter {

    //用户初始化请求接口
    public static List paths= new ArrayList<>();
    static {
        paths.add("/test.json");
    }

    public static void router(String path,OutputStream os) {
        if(!pathCheck(path)){
            p404(os);
            return;
        }else {
            p200(os);
        }
        if("/test.json".equals(path)){
            Map map= new HashMap();
            map.put("you",1);
            map.put("are",2);
            try {
                os.write(JSON.toJSONString(map).getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else if("...".equals(path)){
            //todo
        }else {
            //todo
        }

    }

    private static void p200(OutputStream os){
        String responseFirstLine= "HTTP/1.1 200 OK\r\n";
        String responseHeader="Content-type:"+ContentType.json+"\r\n\r\n";
        try {
            os.write(responseFirstLine.getBytes());
            os.write(responseHeader.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void p404(OutputStream os){
        String responseFirstLine= "HTTP/1.1 404 OK\r\n";
        String responseHeader="Content-type:"+ContentType.json+"\r\n\r\n";
        try {
            os.write(responseFirstLine.getBytes());
            os.write(responseHeader.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static boolean pathCheck(String path){
        for (String p:paths){
            if(p.equals(path)){
                return true;
            }
        }
        return false;
    }
}

4.常量类

package com.example.demo.server.serverSocket;

public class ContentType {
    public static final String html= "text/html";
    public static final String jpg= "image/jpeg";
    public static final String gif= "image/gif";
    public static final String png= "image/png";
    public static final String octetStream= "application/octet-stream";
    public static final String json= "application/json;charset=UTF-8";
}

你可能感兴趣的:(基于ServerSocket模拟web容器)