zoukankan      html  css  js  c++  java
  • 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请求,出现两次的根源。

  • 相关阅读:
    Tips for C++ Primer Chapter 11 关联容器
    Tips for C++ Primer Chapter 10 泛型算法
    Tips for C++ Primer Chapter 9 顺序容器
    Tips for C++ Primer Chapter 8 IO库
    Trie Tree 字典树
    Manacher Algorithm 最长回文子串
    【Android Studio】android Internal HTTP server disabled 解决
    释放修改OS X 10.11系统文件权限【转】
    win10 Vmware12装mac os X10.11虚拟机教程
    【Android开发实践】android.view.InflateException: Binary XML file line #12: Error inflating class fragment问题解决
  • 原文地址:https://www.cnblogs.com/hello-yz/p/10854495.html
Copyright © 2011-2022 走看看