美文网首页
基于ServerSocket模拟web容器

基于ServerSocket模拟web容器

作者: 离别刀 | 来源:发表于2018-05-22 15:39 被阅读0次
    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<String,Object> requestParameters(String request){
            Map<String,Object> map= new HashMap<>();
            String path= null;
            try {
                String[] lines= request.split("\r\n");
                for(int i=0;i<lines.length;i++){
                    String line= lines[i];
                    if(i==0){
                        String[] parts= line.split(" ");
                        path= parts[1];
                        map.put("methodType",parts[0]);
                        map.put("path",path);
                        map.put("protocol",parts[2]);
                    }else if(i==lines.length-1 && path.indexOf(".json")>-1){
                        Map<String,String> 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<String,Object> 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<String> 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容器

          本文链接:https://www.haomeiwen.com/subject/xqzhjftx.html