1. 程式人生 > >使用socket模擬tomcat實現靜態資源處理

使用socket模擬tomcat實現靜態資源處理

步驟:

1.服務端使用ServerSocket,監聽指定的埠。 2.呼叫ServerSocket的accept方法接收客戶端連線,得到Socket物件。 3.根據Socket物件的getInputStream()方法得到輸入流,從而拿到瀏覽器傳送的http請求的基本資訊。

GET /htmlfiles/test2.jsp HTTP/1.1
Host: localhost:9191
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: Hm_lvt_9bd56a6d0766b887592ee921aa94763f=1500436957; __atuvc=47%7C35; _ga=GA1.1.2016651800.1504071340; Hm_lvt_4e003ba2028a4a83d95714c602ee7df5=1507970222; Hm_lvt_47acec2d282c3986f1b600abdc11c7ab=1520665960,1521097911,1521252255,1521540649

4.解析http請求,提取要訪問的資原始檔的位置,使用Socket的getOutputStream拿到輸出流,將檔案的內容寫到輸出流。 5.資源請求完畢,關閉相關的流和Socket。

程式碼

public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket(9191)
; System.out.println("Server已在埠9191啟動!"); while (true) { socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); Request request = new Request(inputStream); OutputStream outputStream = socket.
getOutputStream(); Response response = new Response(outputStream, request); response.response(); outputStream.close(); inputStream.close(); socket.close(); } } catch (IOException e) { e.printStackTrace(); } finally { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class Request {
    private String uri;
    public Request(InputStream in) {
        try {
            String content = IOUtils.getRequestContent(in);
            if (null == content || "".equals(content)) {
                System.out.println("Bad request.");
                return;
            }
            System.out.println("客戶端請求:\n" + content);
            parseUri(content);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void parseUri(String content) {
        this.uri = content.substring(content.indexOf("/"),content.indexOf("HTTP/")-1);
    }
    public String getUri() {
        return uri;
    }
    public void setUri(String uri) {
        this.uri = uri;
    }
}
public class Response {
    private Request request;
    private OutputStream os;
    public Response(OutputStream os, Request request) {
        this.os = os;
        this.request = request;
    }
    public void response() {
        String uri = request.getUri();
        if (null != uri && !"".equals(uri)) {
            if (isResource()) {
                String path = Http_Server.WEB_ROOT + uri.substring(1);
                if (IOUtils.isFileExist(path)) {
                    IOUtils.writeFile(os, path);
                } else {
                    String errorMessage = buildResponse("File Not Found","404","");
                    IOUtils.write(os, errorMessage.getBytes());
                }
            } else {
                String errorMessage = buildResponse("動態請求暫不支援","200","OK");
                IOUtils.write(os, errorMessage.getBytes());
            }
        }
    }
    private String buildResponse(String content, String statusCode, String statusMsg) {
        String html = buildHTML(content);
        int chineseCount = StringUtils.getChineseCharCount(html);
        StringBuffer buffer = new StringBuffer();
        buffer.append("HTTP/1.1 ")
                .append(statusCode).append(" ")
                .append(statusMsg).append("\r\n")
                .append("Content-Type: text/html\r\n")
//                .append("Content-Length: ")
//                .append(html.length()+2*chineseCount) // 1箇中文字元佔3個位元組
                .append("\r\n\r\n")
                .append(html);
        return buffer.toString();
    }
    private String buildHTML(String content) {
        StringBuffer html = new StringBuffer();
        html.append("<html>\n");
        html.append("<head>\n");
        html.append("<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n");
        html.append("</head>\n");
        html.append("<body>\n");
        html.append("<h1>").append(content).append("</h1>\n");
        html.append("</body>\n");
        html.append("</html>");
        return html.toString();
    }
    private boolean isResource() {
        String[] suffixs = {"html", "js", "css", "jpg", "jpeg", "gif", "bmp"};
        for (String suf : suffixs) {
            if (request.getUri().endsWith("." + suf)) {
                return true;
            }
        }
        return false;
    }
}
public class IOUtils {
    public static String getRequestContent(InputStream inputStream) throws IOException {
        byte[] data = new byte[2048];
        int len = inputStream.read(data);
        if (len > 0) {
            return new String(data,0,len);
        }
        return null;
    }
    public static boolean isFileExist(String path) {
        File file = new File(path);
        return file.exists();
    }
    public static byte[] getFileContent(String path) {
        try {
            File file = new File(path);
            if (file.exists()) {
                byte[] data = new byte[(int) file.length()];
                FileInputStream fis = new FileInputStream(file);
                fis.read(data);
                return data;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void write(OutputStream os,byte[] data) {
        try {
            os.write(data);
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void writeFile(OutputStream os,String path) {
        FileInputStream fis = null;
        try {
            int BUFFER_SIZE = 1024;
            fis = new FileInputStream(path);
            byte[] data = new byte[BUFFER_SIZE];
            int len = fis.read(data,0,BUFFER_SIZE);
            boolean isFirst = true;
            while (len != -1) {
                if (isFirst) {
                    os.write("HTTP/1.0 200 OK\r\n".getBytes());
                    os.write("\r\n".getBytes());;// 根據 HTTP 協議, 空行將結束頭資訊
                    isFirst = false;
                }
                os.write(data,0,len);
                len = fis.read(data,0,BUFFER_SIZE);
                os.flush();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
public class Http_Server {
    public final static String WEB_ROOT = Http_Server.class.getResource("/").getPath();
}

測試HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>測試頁面</title>
    <link href="/htmlfiles/css/test.css" rel="stylesheet">
</head>
<body>
    <h1>這是測試頁面。<br></h1>
    <a href="http://localhost:9191/htmlfiles/images/1.jpg">點選開啟圖片</a>
</body>
</html>

資原始檔放在src目錄下。如圖:

測試

1.動態請求測試

2.不存在的靜態檔案

3.存在的靜態檔案

4.圖片等二進位制檔案測試

注意

1.你得通過響應頭告訴瀏覽器請求的狀態碼和資源型別,否則瀏覽器會告訴你這是無效的http響應。

os.write("HTTP/1.0 200 OK\r\n".getBytes());
os.write("\r\n".getBytes());;// 根據 HTTP 協議, 空行將結束頭資訊

2.如果指定了Content-Length,需要注意中文1個字元佔用3個位元組,否則會導致瀏覽器顯示不全。

buffer.append("Content-Length: ")
buffer.append(html.length()+2*chineseCount) // 1箇中文字元佔3個位元組