从 socket 和 inputStream 读取缓慢

Posted

技术标签:

【中文标题】从 socket 和 inputStream 读取缓慢【英文标题】:Slow reading from socket and inputStream 【发布时间】:2015-05-23 00:59:35 【问题描述】:

我使用 java.net.Socket 在我的应用程序中接收消息。接收非常慢。接收 250 kB 的时间超过 7 秒。我能做些什么来加速这一点。 7秒太长了……

InputStream is = null;
byte[] arr = new byte[8192];
try 
    is = client.getInputStream();
 catch (IOException e) 
    e.printStackTrace();


int bytesNumber;
StringBuffer sb = new StringBuffer();

try 
    while ((bytesNumber = is.read(arr)) >= 0) 
        if (bytesNumber == 8192) 
            sb.append(arr);
            continue;
         else 
            for (int i = 0; i < bytesNumber; i++) 
                sb.append(arr[i]);
            
        
    
 catch (IOException e) 
    e.printStackTrace();

【问题讨论】:

什么是tab?你有is.read(tab) 首先,您的代码与您添加内容的方式完全不正确。其次,代码通常不是接收数据速度的限制——客户端的上传速度和服务器的下载速度通常是速度受限的原因。 那么快速读取数据的最佳方法是什么? 【参考方案1】:

这是因为如果您读取的内容少于缓冲区 (arr) 长度,您将一个接一个地附加字符。而是附加整个缓冲区内容,不需要 if:

sb.append(arr,0,butesNumber);

【讨论】:

然后将其转换为字符串。然而,问题是您的 arr 内容一一附加。 我真的怀疑这个循环是否会对执行时间产生任何影响,即使它不是正确的方式。 只有一种方法可以确定 :) 可能服务器部分也在一个一个地发送字节......【参考方案2】:

正如修补匠所说,通常最大的限制是客户端和服务器网络。但是你可以大大简化你所拥有的。另外,在我看来,你的 8K 缓冲区太小了。除非您有严重的内存限制,否则请使用 1M 或更大。

public String readClient(Client client) throws IOException
    final int bufferSize = 1024 << 9;

    BufferedInputStream in = new BufferedInputStream(client.getInputStream(),bufferSize);
    byte[] bytes = new byte[bufferSize];
    int bytesRead;
    StringBuilder sb = new StringBuilder(bufferSize);
    try 
        while ((bytesRead = in.read(bytes)) != -1) 
            sb.append(new String(bytes, 0, bytesRead));
        
    finally 
        in.close();
    
    return sb.toString();

【讨论】:

为什么要为字符串缓冲区预分配 buffferSize/2? 因为保持一致实在是太无聊了。 为什么他需要一个 1M 的缓冲区来存储 250k 个文件?应用程序缓冲区应该与底层套接字的发送/接收缓冲区匹配。 谁说它永远是 250K?我不认为需要有限制。 JDK 读入流缓冲区,直到被套接字阻塞。套接字可能不会被较小的缓冲区阻塞。【参考方案3】:

性能如此糟糕不太可能是由于您的代码造成的。在同一系统之间使用curl 或类似的东西可以获得什么样的性能?

更大的问题是你的代码不可能做你想做的事。目前,您正在将字节数组的表示附加到字符串,或将字节的十进制表示附加到该字符串。如果服务器发送“Hello, World!”,你最终会得到一个字符串“7210110810811144328711111410810033”。对于较长的文件,您会看到类似“[B@76c5a2f7”的内容弹出,这是字节数组的打印方式。

假设您正在接收使用 UTF-8 编码的文本,我会这样写:

CharArrayWriter str = new CharArrayWriter();
try (InputStream is = client.getInputStream()) 
  Reader r = new InputStreamReader(is, StandardCharsets.UTF_8);
  char[] buffer = new char[8192];
  while (true) 
    int n = r.read(buffer);
    if (n < 0)
      break;
    str.write(buffer, 0, n);
  

System.out.println(str);

【讨论】:

以上是关于从 socket 和 inputStream 读取缓慢的主要内容,如果未能解决你的问题,请参考以下文章

从 InputStream 读取时,Android Socket BufferedReader readLine() 不起作用

取消从 InputStream 读取

读取 NANOHTTPD 的 InputStream 会产生 Socket TimeOut 异常

从套接字和inputStream读取缓慢

Java 套接字:InputStream.read() 与 BufferedReader.read()

关于InputStream类的available()方法