使用 ByteBuffer 从 Socket 读取的更快方法?

Posted

技术标签:

【中文标题】使用 ByteBuffer 从 Socket 读取的更快方法?【英文标题】:Faster way to read from Socket with ByteBuffer? 【发布时间】:2014-03-26 20:16:36 【问题描述】:

我已经通过 TCP 连接到一个不断发送大量数据的套接字,我需要读取这些数据。到目前为止,我所拥有的是一个字节缓冲区,它在 while 循环中逐字节读取。但是我现在使用的测试用例大约是3MB,逐字节读取需要一段时间。

这是我的解释代码:

ByteBuffer buff = ByteBuffer.allocate(3200000);
while(true)

     int b = in.read();
     if(b == -1 || buff.remaining() == 0)
     
           break;
     
     buff.put((byte)b);

我知道字节缓冲区不是线程安全的,我不确定是否可以通过一次读取多个字节然后将其存储在缓冲区中来加快速度?我有什么方法可以加快这个过程?

【问题讨论】:

你是否从多个线程读取同一个套接字?您是否将填充的缓冲区传递给另一个线程?你为什么要提到线程安全? 在任何语言中(我对 Java 知之甚少),如果您一次只处理读取数据 1 个字节,那么您做错了。读入块,一次处理 1 个字节。 @erickson 我没有使用线程。我说过,因为我在其他地方读过 ByteBuffers 不是线程安全的。但是是的,我正在从单个套接字读取。 @SanJacinto 这也是我的假设哈哈。您是否知道以字节为单位读取的某种标准。 (我的意思是我应该一次读多少字节到一个块中?有标准数量吗?) 这在很大程度上取决于您的应用程序。一般而言,您会在场景允许的情况下阅读尽可能多的内容,这因场景而异。 【参考方案1】:

使用批量读取而不是单字节读取。

byte[] buf = new byte[3200000];
int pos = 0;
while (pos < buf.length) 
  int n = in.read(buf, pos, buf.length - pos);
  if (n < 0)
    break;
  pos += n;

ByteBuffer buff = ByteBuffer.wrap(buf, 0, pos);

您可以将get the SocketChannelread() 直接发送到ByteBuffer,而不是从套接字获取InputStream 并填充要包装的字节数组。

【讨论】:

我相信这行得通,我现在正在运行它,但我不完全确定它会快多少。但我还有一个问题,有没有办法在不知道发送量的情况下从套接字读取? (换句话说,一个未知的缓冲区大小) @GBoggs 您的意思是要避免硬编码最大值,例如本例中的 3200000?相反,是否根据需要动态分配内存以适应从套接字读取的数据?【参考方案2】:

有几种方法。

    使用Channels.newChannel()从输入流中获取通道,使用ReadableByteChannel.read(buffer).

    使用buffer.array() 从缓冲区中获取byte[] 数组并使用in.read(array). 直接读取该数组 当然,确保BB 确实有一个数组。如果它是直接字节缓冲区,则不会,但在这种情况下,您根本不应该这样做,您应该使用 SocketChannel,否则收益为零。

    读入您自己的大字节数组,然后使用批量放入ByteBuffer,注意使用read() 方法返回的长度。

    不要这样做。下定决心是要InputStreams 还是ByteBuffers,不要混用你的编程隐喻。

【讨论】:

以上是关于使用 ByteBuffer 从 Socket 读取的更快方法?的主要内容,如果未能解决你的问题,请参考以下文章

为啥websocket传不了bytebuffer

Java 中 ByteBuffer 的使用说明

从长度为无符号整数的 ByteBuffer 中读取 UTF-8 字符串

从 ByteBuffer 读取前四个字节,然后将它们写回?

如何在本机中写入/读取直接 ByteBuffer?

如何从javascript客户端onmessage函数发送/读取java ByteBuffer(websocket)