美文网首页
开发HTTP服务器 简易版

开发HTTP服务器 简易版

作者: Wpixel | 来源:发表于2018-08-29 13:58 被阅读0次

    子曰:“弟子,入则孝,出则弟,谨而信,凡爱众,而亲仁。行有余力,则以学文。”

    为了更好的理解netty框架,所以就自己写了一个http服务器(少了一个session)

    1 Http解码器和编码器

    1 .1 http解码器接口
    import java.io.BufferedReader;
    import java.io.IOException;
    
    public interface HttpDecode {
    
        String decode(BufferedReader reader) throws IOException, Exception;
    }
    
    1.2 http编码器接口
    import java.io.IOException;
    import java.io.OutputStream;
    
    public interface HttpEncode {
    
        String encode(OutputStream out) throws IOException;
    }
    

    2 实现Http请求和响应 (request和response)

    2.1 实现HttpRequest
    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    import java.util.HashMap;
    import java.util.Map;
    
    public class HttpRequest {
    
        private String requestLine;
        private RequestHeader header;
        private Map<String, String> keyValue;
        private String body;
        
        public static final String GET = "GET";
        public static final String POST = "POST";
        //静态文件
        private String resources;
        
        public String getUri(){
            String uris = requestLine.split(" ")[1];
            if(uris.indexOf("?") != -1){
                return uris.split("\\?")[0];
            }else{
                return uris;
            }
        }
        
        /**
         * 获取参数
         * @return
         */
        public String getParameter(String key) {
            try {
                if(keyValue.get(key) != null && !keyValue.get(key).equals("")){
                    return URLDecoder.decode(keyValue.get(key),"UTF-8");
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return "";
        }
        
        /**
         * 初始化map
         * @return
         */
        public Map<String, String> initMap(){
            keyValue = new HashMap<String, String>();
            return keyValue;
        }
        public void removeMap(){
            keyValue = null;
        }
        
        public String getRequestLine() {
            return requestLine;
        }
        public void setRequestLine(String requestLine) {
            this.requestLine = requestLine;
        }
        public RequestHeader getHeader() {
            return header;
        }
        public void setHeader(RequestHeader header) {
            this.header = header;
        }
        public String getResources() {
            return resources;
        }
        public void setResources(String resources) {
            this.resources = resources;
        }
        public String getBody() {
            return body;
        }
        public void setBody(String body) {
            this.body = body;
        }
    }
    
    2.2实现HttpResponse
    public class HttpResponse {
    
        private String write;
    
        public String getWrite() {
            return write;
        }
    
        public void setWrite(String write) {
            this.write = write;
        }
    }
    

    3 解析请求和响应

    3.1 解析请求HttpRequestDecoder
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.lang.reflect.Method;
    
    public class HttpRequestDecoder implements HttpDecode {
    
        @Override
        public String decode(BufferedReader reader) throws IOException, Exception{
            if(reader != null){
                HttpRequest request = Server.request;
                request.setRequestLine(reader.readLine());
                Class<?> clazz = Class.forName("com.wpixel.http.RequestHeader");
                Object requestHeader = clazz.newInstance();
                String str = "";
                while((str = reader.readLine().trim()) != null && !str.trim().equals("")){
                    String[] split = str.split(": ");
                    String key = "set"+split[0].replaceAll("-", "");
                    Method method = clazz.getMethod(key, String.class);
                    method.invoke(requestHeader, split[1]);
                }
                Method method = clazz.getMethod("getContentLength");
                String len = (String)method.invoke(requestHeader);
                String body = "";
                int g = 1;
                if(len != null){
                    for (int i = 0; i < Integer.valueOf(len); i++) {
                        body += (char) reader.read();
                    }
                }
                request.setBody(body.toString());
                Server.request.setHeader((RequestHeader)requestHeader);
            }
            return null;
        }
        
    }
    
    3.2响应编码HttpResponseEncoder
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.Date;
    
    public class HttpResponseEncoder implements HttpEncode {
    
        @Override
        public String encode(OutputStream out) throws IOException{
            out.write("HTTP/1.1 200 OK\r\n".getBytes());
            out.write("Content-Type: text/html;charset=utf-8\r\n".getBytes());
            out.write("Connection: Keep-Alive\r\n".getBytes());
            out.write("\r\n".getBytes());
            
            File file = new File(Server.response.getWrite());
            InputStream in = new FileInputStream(file);
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            byte[] buffer = new byte[(int)(file.length())];
            int len = 0;
            while ((len = in.read(buffer)) != -1) {
                byteOut.write(buffer, 0, len);
            }
            
            out.write(buffer);
            
            return null;
        }
    }
    

    4 定义一个http请求头demo类

    public class RequestHeader {
        
        private String host;
        private String connection;
        private String contentLength;
        private String cacheControl;
        private String accept;
        private String origin;
        private String upgradeInsecureRequests;
        private String userAgent;
        private String contentType;
        private String referer;
        private String acceptEncoding;
        private String acceptLanguage;
        private String pragma;
        
        public String getContentLength() {
            return contentLength;
        }
        public void setContentLength(String contentLength) {
            this.contentLength = contentLength;
        }
        public String getOrigin() {
            return origin;
        }
        public void setOrigin(String origin) {
            this.origin = origin;
        }
        public String getContentType() {
            return contentType;
        }
        public void setContentType(String contentType) {
            this.contentType = contentType;
        }
        public String getReferer() {
            return referer;
        }
        public void setReferer(String referer) {
            this.referer = referer;
        }
        public String getHost() {
            return host;
        }
        public void setHost(String host) {
            this.host = host;
        }
        public String getConnection() {
            return connection;
        }
        public void setConnection(String connection) {
            this.connection = connection;
        }
        public String getCacheControl() {
            return cacheControl;
        }
        public void setCacheControl(String cacheControl) {
            this.cacheControl = cacheControl;
        }
        public String getAccept() {
            return accept;
        }
        public void setAccept(String accept) {
            this.accept = accept;
        }
        public String getUpgradeInsecureRequests() {
            return upgradeInsecureRequests;
        }
        public void setUpgradeInsecureRequests(String upgradeInsecureRequests) {
            this.upgradeInsecureRequests = upgradeInsecureRequests;
        }
        public String getUserAgent() {
            return userAgent;
        }
        public void setUserAgent(String userAgent) {
            this.userAgent = userAgent;
        }
        public String getAcceptEncoding() {
            return acceptEncoding;
        }
        public void setAcceptEncoding(String acceptEncoding) {
            this.acceptEncoding = acceptEncoding;
        }
        public String getAcceptLanguage() {
            return acceptLanguage;
        }
        public void setAcceptLanguage(String acceptLanguage) {
            this.acceptLanguage = acceptLanguage;
        }
        public String getPragma() {
            return pragma;
        }
        public void setPragma(String pragma) {
            this.pragma = pragma;
        }
    }
    

    5 定义一个数据传输通道

    public class InitChannel {
    
        static SocketChannel channel = null;
        
        public InitChannel() {
            
        }
        
        protected void initSocketChannel(SocketChannel channel) throws Exception {
            
        }
    }
    

    6 定义通道接口

    public interface HttpSimpleHeader {
    
        public void httpWrite() throws Exception;
    }
    

    7 整合http请求的业务处理 (get和post)

    import java.util.Map;
    
    public class SendAndRev implements HttpSimpleHeader {
        
        @Override
        public void httpWrite() throws Exception {
            //初始化参数
            Map<String, String> initMap = Server.request.initMap();
            String method = Server.request.getRequestLine().split(" ")[0];
            if(method.equals(HttpRequest.GET)){
                String path = Server.request.getRequestLine().split(" ")[1];
                String[] split = path.split("\\?");
                if(split.length > 1){
                    String parameter = split[1];
                    String[] parameters = parameter.split("\\&");
                    if(parameters.length != 0){
                        for (String string : parameters) {
                            if(string.split("=").length > 1){
                                initMap.put(string.split("\\=")[0], string.split("\\=")[1]);
                            }
                        }
                    }
                }
                Servlet.doGet(Server.request, Server.response);
            }else if(method.equals(HttpRequest.POST)){
                String body = Server.request.getBody();
                String[] parameters = body.split("\\&");
                if(parameters.length != 0){
                    for (String string : parameters) {
                        if(string.split("=").length > 1){
                            initMap.put(string.split("\\=")[0], string.split("\\=")[1]);
                        }
                    }
                }
                Servlet.doPost(Server.request, Server.response);
            }
        }
    }
    

    8 定义TCP连接

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ServerBootstrap {
    
        ServerSocket server = null;
        InitChannel initChannel = null;
        //使用线程池
        ExecutorService threadPool = null;
        public ServerBootstrap(){
            threadPool = Executors.newFixedThreadPool(4);
        }
         
        public void childHandler(InitChannel initChannel) throws IOException{
            this.initChannel = initChannel;
        }
        public void bind(int port) throws IOException{
            server = new ServerSocket(port);
        }
        
        public void accept() throws Exception{
            while(true){
                Socket socket = server.accept();
                Runnable runnable = () -> {
                    InputStream in = null;
                    OutputStream out = null;
                    try {
                        in = socket.getInputStream();
                        out = socket.getOutputStream();
                        initChannel.initSocketChannel(new SocketChannel(in, out));
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            out.close();
                            in.close();
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName()+"结束");
                };
                threadPool.execute(runnable);
            }
        }
        
    }
    

    9 定义TCP通道

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    
    public class SocketChannel {
        
        private InputStream in;
        private OutputStream out;
        public SocketChannel(InputStream in, OutputStream out){
            this.in = in;
            this.out = out;
        }
        
        //编码器
        public void addEncode(HttpEncode encoder) throws IOException{
            encoder.encode(out);
        }
        
        //解码器
        public void addDecode(HttpDecode decoder) throws Exception{
            decoder.decode(new BufferedReader(new InputStreamReader(in)));
        }
        
        public void addServer(HttpSimpleHeader header) throws Exception{
            header.httpWrite();
        }
    }
    

    10 servlet请求入口

    import java.io.UnsupportedEncodingException;
    
    public class Servlet {
    
        public static void doGet(HttpRequest request, HttpResponse response) {
            System.out.println("doGet");
            String name3 = request.getParameter("name3");
            String name4 = request.getParameter("name4");
            System.out.println("name3:"+name3+";name4:"+name4);
            response.setWrite(System.getProperty("user.dir")+request.getUri());
        }
        
        public static void doPost(HttpRequest request, HttpResponse response) throws UnsupportedEncodingException {
            System.out.println("doPost");
            String name1 = request.getParameter("name1");
            String name2 = request.getParameter("name2");
            System.out.println("name1:"+name1+";name2:"+name2);
            response.setWrite(System.getProperty("user.dir")+request.getUri());
        }
    }
    

    11 http服务启动类

    public class Server {
        
        public static HttpRequest request = null;
        public static HttpResponse response = null;
        public static ServerBootstrap bootstrap = null;
        static{
            request = new HttpRequest();
            response = new HttpResponse();
        }
        
        public static void main(String[] args) {
            System.out.println("启动服务器;端口8080!!!!!");
            try {
                bootstrap = new ServerBootstrap();
                bootstrap.childHandler(new InitChannel(){
                    @Override
                    protected void initSocketChannel(SocketChannel sc) throws Exception {
                        sc.addDecode(new HttpRequestDecoder());
                        sc.addServer(new SendAndRev());
                        sc.addEncode(new HttpResponseEncoder());
                    }
                });
                bootstrap.bind(8080);
                bootstrap.accept();
                
                
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                
            }
        }
    }
    

    12 新建一个网页 index.html

    <!DOCTYPE html>
    <html>
      <head>
        <title>首页</title>
        <meta name="keywords" content="keyword1,keyword2,keyword3">
        <meta name="description" content="this is my page">
        <meta name="content-type" content="text/html; charset=UTF-8">
        <link rel="icon" href="favicon.ico" type="image/x-icon" />
        <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
        <link rel="bookmark" href="favicon.ico" type="image/x-icon" />
        <style>
        </style>
      </head>
      
      <body>
        <h1>This is my HTML page.</h1> 
        <br>
        -----------------静态资源----------------------
        <br>
        <img src="/src/com/wpixel/http/111.jpg" width="300"/>
        <br>
        -----------------post请求-----------------------
        <br>
        <form action="/src/com/wpixel/http/index.html" method="post">
            <p>1name: <input type="text" name="name1" /></p>
            <p>2name: <input type="text" name="name2" /></p>
            <input type="submit" value="Submit" />
        </form>
        <br>
        -----------------get请求-----------------------
        <br>
        <form action="/src/com/wpixel/http/index.html" method="get">
            <p>3name: <input type="text" name="name3" /></p>
            <p>4name: <input type="text" name="name4" /></p>
            <input type="submit" value="Submit" />
        </form>
        <br>
      </body>
    </html>
    

    总结


    作者是一名自由程序员,住在上海,喜欢音乐、小说、旅行、以及编程。

    P.S. 如果您喜欢这篇文章并且希望学习编程技术的话,请关注一下

    相关文章

      网友评论

          本文标题:开发HTTP服务器 简易版

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