将输入流连接到输出流

jbu*_*jbu 72 java inputstream outputstream

java9中的更新:https://docs.oracle.com/javase/9​​/docs/api/java/io/InputStream.html#transferTo-java.io.OutputStream-

我看到了一些相似的,但不是我需要的线程.

我有一个服务器,它基本上从客户端,客户端A接收输入,并逐字节转发到另一个客户端,客户端B.

我想将客户端A的输入流与客户端B的输出流连接起来.这可能吗?有什么方法可以做到这一点?

此外,这些客户端正在发送彼此有时间敏感的消息,因此缓冲不会.我不想要500的缓冲区和客户端发送499个字节,然后我的服务器在转发500个字节时保持关闭,因为它没有收到填充缓冲区的最后一个字节.

现在,我正在解析每条消息以找到它的长度,然后读取长度字节,然后转发它们.我想(并测试)这比读取一个字节并反复转发一个字节更好,因为这将非常慢.我也不想使用缓冲区或计时器,因为我在上一段中说过 - 我不希望消息等待很长时间才能通过,因为缓冲区未满.

这样做的好方法是什么?

Jon*_*eet 84

仅仅因为你使用缓冲区并不意味着流必须填充该缓冲区.换句话说,这应该没问题:

public static void copyStream(InputStream input, OutputStream output)
    throws IOException
{
    byte[] buffer = new byte[1024]; // Adjust if you want
    int bytesRead;
    while ((bytesRead = input.read(buffer)) != -1)
    {
        output.write(buffer, 0, bytesRead);
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该做工精细-基本read调用将阻塞有到一些数据可用,但它不会等到它的所有可用的填充缓冲区.(我想它可以,我相信FileInputStream通常填充缓冲区,但连接到套接字的流更有可能立即为您提供数据.)

我认为至少首先尝试这个简单的解决方案是值得的.

  • @Zibbobz:任何数组大小都可以工作 - 它越大,所需的读取就越少,但它工作时所需的内存就越多.它不一定是流的实际长度. (2认同)

Dea*_*ler 75

如何使用

void feedInputToOutput(InputStream in, OutputStream out) {
   IOUtils.copy(in, out);
}
Run Code Online (Sandbox Code Playgroud)

并完成它?

来自jakarta apache commons i/o库已被大量项目使用,所以你可能已经在你的类路径中已经有了jar.

  • 或者只是使用函数本身,因为不需要使用完全相同的参数调用另一个函数.... (23认同)

Jes*_*eke 21

为了完整起见,番石榴也有一个方便的工具

ByteStreams.copy(input, output);
Run Code Online (Sandbox Code Playgroud)


Ste*_*han 9

您可以使用循环缓冲区:

// buffer all data in a circular buffer of infinite size
CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
class1.putDataOnOutputStream(cbb.getOutputStream());
class2.processDataFromInputStream(cbb.getInputStream());
Run Code Online (Sandbox Code Playgroud)


Maven依赖

<dependency>
    <groupId>org.ostermiller</groupId>
    <artifactId>utils</artifactId>
    <version>1.07.00</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)


模式细节

http://ostermiller.org/utils/CircularBuffer.html


Dan*_*eón 6

实现它的异步方式.

void inputStreamToOutputStream(final InputStream inputStream, final OutputStream out) {
    Thread t = new Thread(new Runnable() {

        public void run() {
            try {
                int d;
                while ((d = inputStream.read()) != -1) {
                    out.write(d);
                }
            } catch (IOException ex) {
                //TODO make a callback on exception.
            }
        }
    });
    t.setDaemon(true);
    t.start();
}
Run Code Online (Sandbox Code Playgroud)