Socket編程之Tomcat模擬_採坑彙總

用java.net.Socket來模擬實現Tomcat,碰到了一些坑,大部分是沒有想到的,記錄下來自查。html

直接上代碼,java

public class TomcatDemo {

    private static ExecutorService executorService = Executors.newCachedThreadPool();

    public static void main(String[] args) throws IOException {
        //監聽9000端口
        @SuppressWarnings("resource")
        ServerSocket serverSocket = new ServerSocket(9000);
        System.out.println("Tomcat服務啓動成功!");
        while (!serverSocket.isClosed()) {
            //阻塞式
            Socket request = serverSocket.accept();
            System.out.println(request.getInetAddress());
            executorService.execute(() -> {
                try {
                    InputStream inputStream = request.getInputStream();
                    System.out.println("收到請求...");
                    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
                    StringBuffer sb = new StringBuffer();
                    String line;
                    while((line = br.readLine()) != null) {
                        sb.append(line).append("\r\n");
                    }
                    System.out.println(sb.toString());
                    //由servlet處理業務邏輯

                    System.out.println("-----------------end");
                    //請求結束...
                    OutputStream outputStream = request.getOutputStream();
                    outputStream.write("HTTP/1.1 200 OK\r\n".getBytes());
                    outputStream.write(("Content-Length: " + "Hello World!".getBytes().length + "\r\n\r\n").getBytes());
                    outputStream.write("Hello World!".getBytes());
                    outputStream.flush();
                    System.out.println("請求結束...");
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        request.close();
                    } catch (Exception e2) {
                        e2.printStackTrace();
                    }
                }

            });
        }
    }

}

運行程序,使用Chrome訪問localhost:9000app

問題有兩個,socket

(1) 居然發起兩次GET請求網站

(2) 出現socket write errorspa

起初開始解決socket write error,大多數說是由於socket提早close或者超時致使的,可是發起的請求尚未結束。後來一步步調試,發現代碼在 line = br.readLine()) != null 處阻塞等待了!.net

原來是br.readLine()的機制同本身想的並不同,它是阻塞式的,叉掉http://localhost:9000/的請求後,後續代碼才繼續被執行。插件

增長以下判斷代碼解決,3d

while((line = br.readLine()) != null) {
    if (line.length() == 0){ break; }
    sb.append(line).append("\r\n");
}

可是socket write error的問題還在,這個應該就和重複請求有關係了。調試

改用Firefox訪問http://localhost:9000/,發現請求正常,

看來是Chrome的問題,遂查了下,應該是插件形成的請求重複發送,這也致使瞭如上socket write error的問題。

用Chrome訪問還會出現請求/favicon.ico,這個是Chrome後臺默默作的,用來顯示和網站相關的信息。這也正是平時你們說的Chrome一次GET請求,出現兩次的根源。

相關文章
相關標籤/搜索