自Java 7以来1s延迟了HttpServer

Dom*_*nik 7 java java-7 com.sun.net.httpserver

我们使用HttpServer项目中的内部类通过HTTP在客户端和服务器之间交换数据.当我们切换到Java 7时,我们意识到结果交付的延迟.我们可以将问题减少到以下示例:

EchoServer创建上下文/echo,该上下文仅在每个请求时返回当前日期和请求URI.然后,客户端在循环中调用此服务.

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.Date;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class EchoServer {

    public static void main(String[] args) throws IOException {
        HttpServer server = HttpServer.create(new InetSocketAddress(80), 0);
        server.createContext("/echo", new EchoHandler());
        server.start();
    }

    static class EchoHandler implements HttpHandler {
        public void handle(HttpExchange httpExchange) throws IOException {
            httpExchange.getResponseHeaders().add("Content-type", "text/html");
            String response = "<b>" + new Date() + "</b> for "  + httpExchange.getRequestURI();
            httpExchange.sendResponseHeaders(200, response.length());
            OutputStream os = httpExchange.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下客户端使用类在无限循环中调用服务,URL并从返回的流中打印出第一个字符(这将是<符号).此外,客户端打印当前时间.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;

public class EchoClient {

    public static void main(String[] args) throws Exception{
        while(true) {
            URL url = new URL("http://localhost:80/echo");

            BufferedReader rd = new BufferedReader(new InputStreamReader(url.openStream()));
            int res = rd.read();
            System.out.println((char)res);
            System.out.println(System.currentTimeMillis());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果在Java6上执行此代码,一切正常,结果打印约.每5毫秒.

% java -version
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)

% java EchoClient
<
1362515635677
<
1362515635682
<
1362515635687
<
1362515635691
Run Code Online (Sandbox Code Playgroud)

如果代码在Java7上执行,则每个请求大约使用1000毫秒.

% java -version
java version "1.7.0_17"
Java(TM) SE Runtime Environment (build 1.7.0_17-b02)
Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)

% java EchoClient
<
1362517297845
<
1362517298844
<
1362517299845
<
1362517300845
Run Code Online (Sandbox Code Playgroud)

似乎在某处隐藏了1000毫秒的超时.如果角色读的InputStreamReader,而不是在BufferedReader,同样的延迟现象.如果直接从输入流中读取一个字节,则无法看到延迟.在另一方面,如果该EchoClient程序是对一个servlet运行,那么一切工作正常,独立的有无BufferedReaderInputStreamReader使用.

看来,该类InputStreamReader期望来自服务器的东西不再由HttpServer的Java 7实现提供.你知道这里到底发生了什么,以及如何解决这个问题?解决方法?或者这是一个错误?

谢谢!


我在客户端代码中添加了更多时间:

public static void main(String[] args) throws Exception{
    while(true) {
        System.out.println("0: "+System.currentTimeMillis());
        URL url = new URL("http://localhost:80/echo");
        System.out.println("1: "+System.currentTimeMillis());
        InputStream in = url.openStream();
        System.out.println("2: "+System.currentTimeMillis());
        InputStreamReader isr = new InputStreamReader(in);
        System.out.println("3: "+System.currentTimeMillis());
        char res = (char)isr.read(); // character read is `<`
        System.out.println(res + ": "+System.currentTimeMillis());
    }
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

% java EchoClient
0: 1362532555535
1: 1362532555537
2: 1362532555608
3: 1362532555609
<: 1362532555611
0: 1362532555612
1: 1362532555613
2: 1362532556608
3: 1362532556609
<: 1362532556610
0: 1362532556611
1: 1362532556612
2: 1362532557609
3: 1362532557610
<: 1362532557611
0: 1362532557612
1: 1362532557613
Run Code Online (Sandbox Code Playgroud)

第一次调用openStream需要一些时间(70ms),但所有进一步的调用openStream需要更长的时间(大约996ms).

mat*_*t b 1

您似乎没有关闭 BufferedReader 或 返回的 InputStream url.openStream()。不关闭流可能会导致在后续迭代中重用连接时出现问题(通常是错误行为)。

显式调用 和 会得到不同的结果rd.close()stream.close()