自Java 7以来1s延迟了HttpServer [英] 1s Delay in HttpServer since Java 7

查看:119
本文介绍了自Java 7以来1s延迟了HttpServer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We are using the internal HttpServer class in a project to exchange data between a client and a server over HTTP. As we switched to Java 7, we realized a delay in the delivery of the results. We could reduce the problem to the following sample:

EchoServer 创建上下文 / echo ,它只是在每次请求时返回当前日期和请求URI。然后,客户端在循环中调用此服务。

Class EchoServer creates the context /echo which simply returns the current date and the request URI upon each request. This service is then invoked by a client in a loop.

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();
        }
    }
}

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

The following client invokes the service in an infinite loop using class URL and prints the first character from the returned stream (which will be the < sign). In addition, the client prints the current time.

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());
        }
    }
}

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

If this code is executed on Java6, everything works fine and a result is printed approx. every 5 ms.

% 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

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

If the code is executed on Java7, then each request uses 1000ms approx.

% 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

似乎某处隐藏了1000毫秒的超时。如果在 InputStreamReader 上读取字符而不是 BufferedReader ,则会发生相同的延迟。
如果直接从输入流中读取一个字节,则无法看到延迟。另一方面,如果 EchoClient 程序是针对servlet运行的
,那么一切正常,无论 BufferedReader InputStreamReader

It seems that a timeout of 1000ms is hidden somewhere. If the character is read on the InputStreamReader instead over the BufferedReader, the same delay happens. If a byte is read from the input stream directly, then no delay can be seen. On the other hand, if the EchoClient program is run against a servlet, then everything works fine, independent of whether the BufferedReader or the InputStreamReader is used.

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

It seems, that class InputStreamReader is expecting something from the server which is no longer delivered by the Java 7 implementation of HttpServer. Do you have an idea what exactly happens here and how this problem could be resolved? A workaround? Or is this a bug?

谢谢!

I已经为客户端代码添加了更多时间:

I have added further timings to the client code:

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());
    }
}

,结果如下:

% 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

第一次调用 openStream 需要一些时间(70ms),但还需要一些时间调用 openStream 需要更长的时间(约996毫秒)。

The first invocation of openStream takes some time (70ms), but all further invocations of openStream take much longer (996ms approx).

推荐答案

向Oracle提交了一份错误报告。这两个Java版本(SE 6或7)都有38毫秒的延迟。

Just filed a bug report with Oracle. I'm getting a 38 ms delay here for both Java releases (SE 6 or 7).

/**
 * @test
 * @bug 
 * @summary  pipelining delay on Ubuntu 12.04.01 LTS / amd64
 */

import com.sun.net.httpserver.*;

import java.util.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;

public class Bug {

    static int iterations = 20;
    static long requiredMinimumDelay = 10L;

    public static void main (String[] args) throws Exception {
        Handler handler = new Handler();
        InetSocketAddress addr = new InetSocketAddress (0);
        HttpServer server = HttpServer.create (addr, 0);
        HttpContext ctx = server.createContext ("/test", handler);
        ExecutorService executor = Executors.newCachedThreadPool();
        server.setExecutor (executor);
        server.start ();

        long minDelay = requiredMinimumDelay * 1000L;

        try {
            for(int i = 0; i < iterations; i++) {
                URL url = new URL ("http://localhost:"+server.getAddress().getPort()+"/test/foo.html");
                HttpURLConnection urlc = (HttpURLConnection)url.openConnection ();
                InputStream is = urlc.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String res = br.readLine();
                br.close();

                // skip first few
                if(i < iterations/2) {
                    continue;
                }

                long delay = System.currentTimeMillis() - Long.parseLong(res);
                System.out.println("delay: "+delay+" ms");
                if(delay < minDelay) {
                    minDelay = delay;
                }
            }
        } catch (Exception ex) {}

        server.stop(2);
        executor.shutdown();

        if(minDelay > requiredMinimumDelay) {
            throw new Exception("minimum delay too large: "+minDelay);
        }
    }

    static class Handler implements HttpHandler {
        public void handle (HttpExchange t)
            throws IOException
        {
            InputStream is = t.getRequestBody();
            Headers map = t.getRequestHeaders();
            Headers rmap = t.getResponseHeaders();
            while (is.read () != -1) ;
            is.close();
            String response = Long.toString(System.currentTimeMillis())+"\n";
            t.sendResponseHeaders (200, response.length());
            OutputStream os = t.getResponseBody();
            os.write (response.getBytes());
            t.close();
        }
    }    
}

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8009548

更新:事实证明,甲骨文把它归类为两个不同的错误,一个是38毫秒(他们用来点什么?),一个是1000毫秒,他们在这里解决了:

Update: turns out Oracle classified it as "two different bugs" one for the 38ms (which they punted on?) and one for the 1000ms one, which they resolved here:

http:/ /bugs.java.com/bugdatabase/view_bug.do?bug_id=8014254

因此希望在8b91和7u85版本中修复1000毫秒基于链接的backports。

So the 1000ms one hopefully fixed in versions "8b91" and "7u85" based on the backports linked.

这篇关于自Java 7以来1s延迟了HttpServer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆