Java 套接字缓冲区大小动态

Java 套接字缓冲区大小动态,java,network-programming,Java,Network Programming,我开发了一个带有图形的速度测试软件。每秒钟,我在图表上画出吞吐量。我在套接字上使用带循环的套接字。读取(…) 问题是缓冲区大小。如果我将缓冲区设置为32ko,当速度较低时,我的图形是错误的(在缓冲区未满之前阻塞读取功能)。如果我将缓冲区设置为512个八位字节,则速度为“法兰” 如何动态设置缓冲区大小?一种可能性是选择较小的缓冲区大小,并在绘制它们之前将观察值记录下来 过滤器很容易实现,但需要校准。对于这个应用程序,我会手动调整参数,直到生成的图形的平滑度达到令人满意的程度 阻止读取函数,直到缓冲

我开发了一个带有图形的速度测试软件。每秒钟,我在图表上画出吞吐量。我在套接字上使用带循环的套接字。读取(…)

问题是缓冲区大小。如果我将缓冲区设置为32ko,当速度较低时,我的图形是错误的(在缓冲区未满之前阻塞读取功能)。如果我将缓冲区设置为512个八位字节,则速度为“法兰”


如何动态设置缓冲区大小?

一种可能性是选择较小的缓冲区大小,并在绘制它们之前将观察值记录下来

过滤器很容易实现,但需要校准。对于这个应用程序,我会手动调整参数,直到生成的图形的平滑度达到令人满意的程度

阻止读取函数,直到缓冲区未满

我不知道那是什么意思。套接字读取不会尝试填充缓冲区,而是等待一些数据到达,然后将其移动到缓冲区中,无论其长度如何,直到达到缓冲区的大小。当速度较低时,缓冲区的大小应该没有影响。它将在高速时生效。

您可以调整recv(和发送)缓冲区的大小,如下所示:

    int oldsize = sock.getReceiveBufferSize();
    sock.setReceiveBufferSize(oldsize * 2);
虽然这不是一个好主意。像这样“动态”调整缓冲区的大小会导致套接字内部发生至少一个大规模的阵列到阵列数据拷贝,这是一个巨大的性能损失。此外,套接字对其最大缓冲区大小有操作系统限制

如果您正在阻止read()调用,那么我猜您使用的是常规IO,而不是NIO。我建议使用预分配、固定大小的中间缓冲区和循环将数据移出套接字:

    /* Init socket here... */
    Socket sock = new Socket(...);

    /* Set time out to next to nothing. */
    sock.setSoTimeout(1);

    /* Setup Streams */
    InputStream is = sock.getInputStream();     

    /*  Pick a buffer size, any reasonable size will do: 1k,2k,4k... */
    byte[] buf = new byte[1024 * 2];
    int lastRead = 0;

    do {
        try {
            lastRead = 0;
            lastRead = is.read(buf);
        } catch (SocketTimeoutException ste) {
          /* Do something, or not.  Your call! */
        }

        /*do something with 'buf' here */

    } while (lastRead > 0);

通过设置较低的读取超时,例如1ms,您的read()调用将不会阻塞(很长时间),并且您仍然能够检测是否有可用数据。由于这可能会在“正常”条件下使用异常进程,因此这实际上接近于滥用java.io。

我将缓冲区设置为32kb,并在调试模式下以5kb/s的速度下载java停止读取功能,时间为3/4秒。我将缓冲区大小更改为5kb,读取时不停止功能。为什么?什么读取功能?我所知道的唯一一个Java方法是DataInputStream.readFully()。答案是,不要调用它,调用read(byte[]buffer)。@claymore1977:一般来说,最大可能的缓冲区大小是多少?老实说,这是一个依赖于操作系统的问题。老实说,我不知道“一般”答案。在操作上,我想不出一个合理的理由来设置套接字缓冲区大小超过默认值。那么上面的代码是错误的,因为lastRead永远不会==0;如果流结束,它将始终为>=1或-1。它返回0的唯一时间是给它一个长度为零的字节[],或者让它读取0字节。如果想知道是否有可用字节,请在套接字输入流上使用available()。用缓冲输入流包装套接字输入流也是非常理想的。默认接收缓冲区通常足够,默认为8k公平地说,上面的代码是伪代码,不会编译。只是举个例子。但要说的是:是的,InputStream.read()在某些情况下可以返回零。一个立即浮现在脑海中的问题是插座是否有。此外,根据文档[InputStream.available()只是一个近似值,因此它的用途相当有限,当然不适合分配缓冲区。(根据文档和经验)超时不会返回零值:“如果超时过期,会引发java.net.SocketTimeoutException,尽管套接字仍然有效。”“如果”(lastRead==0)“”永远不会发生,除非您首先使用零长度数组-这在我看来是个错误。