使用Java I / O在HTTP网络上读取流

时间:2014-05-12 06:52:48

标签: java performance io stream

现在我正在努力提高java I / O的性能。我有一些疯狂的疑问,使用java I / O在网络上读/写流,如下所述。我脑海里浮现出几种意见。但我想清除所有这些

代码

URL url = new URL("http://example.com/connector/url2Service");  

URLConnection urlConnection = url.openConnection(); // Position 1

HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection;

String requestStr = buildRequestString();// Position 2

ByteArrayOutputStream rqByteArrayOutputStream = new ByteArrayOutputStream();
rqByteArrayOutputStream.write(((String)requestStr).getBytes()); // Position 3

httpURLConnection.setDoOutput(true);
httpURLConnection.setUseCaches(false);
httpURLConnection.setDoInput(true);
httpURLConnection.setRequestMethod("POST");

rqByteArrayOutputStream.writeTo(httpURLConnection.getOutputStream()); // Position 4

// Waiting for the response.

InputStream inputStream = httpURLConnection.getInputStream(); // Position 5

ByteArrayOutputStream rsByteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int length = 0;

while ((length = inputStream.read(buffer)) != -1) { // Position 6
    rsByteArrayOutputStream.write(buffer, 0, length);// Position 7
}

String response  = new String(rsByteArrayOutputStream.toByteArray());// Position 8

我的理解

  • 位置1:这将提供与远程资源进行通信的对象。但是尚未建立联系。
  • 位置2:构建并获取请求。
  • 位置3:将字节写入ByteArrayOutputStream。
  • 位置4:这是与服务器进行通信的地方。我们正在编写字节。因此,服务器可以开始读取它们。当执行退出此行时,我们已完成发送请求对象。
  • 位置5:当我们退出此行时,服务器已完成发送响应对象。所以,我们可以开始阅读响应对象了。
  • 位置6:将对象读取为4096字节块。
  • 位置7:将读取的字节写入ByteArrayOutputStream。
  • 位置8:完成读取响应并将其转换为字符串。

我的问题

  1. 我们可以说上传请求的重点是什么 完成? (一世 相信这是在我们执行存在位置时完成的 4)
  2. 重点是什么 我们可以说响应下载完成了吗? (我对第5点和第8点有疑问)
  3. 当我们退出第5点时,这意味着响应是完全的 已下载或刚开始下载?
  4. 网络(带宽)将对性能产生什么影响? (第5,6,7 ......)
  5. 现在我正在调整InputStream读取代码。如果您有任何建议请分享?
  6. 参考文献:

3 个答案:

答案 0 :(得分:3)

  

我们可以说请求上传完成了吗? (我相信当执行存在位置4时,这就完成了)

是的,但是你已经浪费了一些ByteArrayOutputStream。只需将请求直接写入连接输出流即可。节省内存和延迟。

  

我们可以说响应下载完成了什么? (我对第5点和第8点有疑问)

当你从read()方法收到-1时。

  

当我们退出Point 5时,是否意味着响应已完全下载或刚开始下载?

都不是。请求已写入,您尚未开始加载任何内容,因此未下载任何内容。它可能已经在套接字接收缓冲区中到达,但你看不到它。

  

网络(带宽)将在何时对性能产生影响? (第5,6,7 ......)

没有一个。在获得-1之前,您正在使用网络带宽。

  

现在我正在调整InputStream读取代码。如果您有任何建议请分享?

使用更大的缓冲区。你无能为力。

答案 1 :(得分:2)

  1. 在建立连接时,请求可以缓冲在系统缓冲区中,因此在您通过位置6之前,请求的发送 - “上传” - 不能保证完成。此时,您知道服务器已收到get请求,因为它现在正在发送响应。传递位置4只意味着您的程序已将请求传递到您自己的系统缓冲区。

  2. 收到回复 - “下载”已完成 - 在最后一次到第6位之后,当它返回-1结束流时。

  3. 当您退出第5位时,可能已收到或未收到回复。您所做的只是获得对已存在的输入流的显式访问。响应已经完全接收并且已经缓冲在系统TCP缓冲区中,并且可能尚未收到任何响应。

  4. 您必须从位置4到位置6的最后一次迭代打开网络资源。在您的代码中,您将继续无限期地保持连接打开状态。退出6/7 while循环后,您可以通过关闭连接来节省网络资源。

  5. (a)不要打扰rqByteArrayOutputStream。而是将输出流从OutputStreamWriter中的连接包装起来,并将请求字符串直接写入该输出流。这样可以节省几行代码,并删除一次复制请求字符串的迭代。

  6. (b)完成输出流和输入流后调用close(),以释放网络资源。

答案 2 :(得分:2)

JDK Http相关类基于旧的java.io实现。检查HttpURLConnection of OpenJDK处的代码。 (Details on the OpenJDK roots, based on Oracle JDK 7)使用基于操作系统原语的新java.nio实现直接提供了一个全新的性能范围。 NIO =非阻塞IO或事件驱动的IO。

Netty是一个基于java.nio原语构建的高性能网络实现。我参与了一个项目,其中netty被开发用于在太阳刀片硬件上实现5位数性能。可以找到Netty示例http代码here

来自LMAX的Martin Thompson撰写的另一篇关于ByteArrayOutputStream性能的文章是java serialization。这可以更深入地了解java性能或内置JDK类性能。

这是您要查找的信息,还是由于遗留的JDK代码库而严格使用的java.io?