Socket编程之Tomcat模拟_采坑汇总

用java.net.Socket来模拟实现Tomcat,碰到了一些坑,大部分是没有想到的,记录下来自查。

直接上代码,

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("
");
                    }
                    System.out.println(sb.toString());
                    //由servlet处理业务逻辑

                    System.out.println("-----------------end");
                    //请求结束...
                    OutputStream outputStream = request.getOutputStream();
                    outputStream.write("HTTP/1.1 200 OK
".getBytes());
                    outputStream.write(("Content-Length: " + "Hello World!".getBytes().length + "

").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:9000

问题有两个,

(1) 竟然发起两次GET请求

(2) 出现socket write error

起初开始解决socket write error,大多数说是因为socket提前close或者超时导致的,但是发起的请求还没有结束。后来一步步调试,发现代码在 line = br.readLine()) != null 处阻塞等待了!

原来是br.readLine()的机制同自己想的并不一样,它是阻塞式的,叉掉http://localhost:9000/的请求后,后续代码才继续被执行。

增加如下判断代码解决,

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

但是socket write error的问题还在,这个应该就和重复请求有关系了。

改用Firefox访问http://localhost:9000/,发现请求正常,

看来是Chrome的问题,遂查了下,应该是插件造成的请求重复发送,这也导致了如上socket write error的问题。

用Chrome访问还会出现请求/favicon.ico,这个是Chrome后台默默做的,用来显示和网站相关的信息。这也正是平时大家说的Chrome一次GET请求,出现两次的根源。

原文地址:https://www.cnblogs.com/hello-yz/p/10854495.html