Подключение входного streamа к выходному streamу

обновление в java9: https://docs.oracle.com/javase/9/docs/api/java/io/InputStream.html#transferTo-java.io.OutputStream-

Я видел некоторые похожие, но не совсем-то-то-нужны streamи.

У меня есть сервер, который будет в основном принимать данные от клиента, клиента A и пересылать его, байт для байта, другому клиенту, клиенту B.

Я хотел бы связать свой входной stream с клиентом A с моим streamом вывода клиента B. Возможно ли это? Каковы способы сделать это?

Кроме того, эти клиенты отправляют друг другу сообщения, которые чувствительны к времени, поэтому буферизация не будет выполняться. Я не хочу, чтобы буфер говорил 500, а клиент отправляет 499 байт, а затем мой сервер держится при пересылке 500 байтов, потому что он не получил последний байт, чтобы заполнить буфер.

Прямо сейчас, я разбираю каждое сообщение, чтобы найти его длину, затем чтение байтов длины, а затем их пересылку. Я решил (и испытал), что это будет лучше, чем чтение байта и пересылка байта снова и снова, потому что это будет очень медленно. Я также не хотел использовать буфер или таймер по той причине, о которой я говорил в своем последнем абзаце, – я не хочу, чтобы сообщения ожидали очень долгое время, чтобы пройти через просто потому, что буфер не заполнен.

Каков хороший способ сделать это?

    Просто потому, что вы используете буфер, это не означает, что stream должен заполнить этот буфер. Другими словами, это должно быть хорошо:

    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); } } 

    Это должно работать нормально – в основном вызов read будет блокироваться до тех пор, пока не будут доступны некоторые данные, но он не будет ждать, пока все они будут доступны для заполнения буфера. (Я полагаю, что это возможно, и я считаю, что FileInputStream обычно заполняет буфер, но stream, подключенный к сокету, скорее всего, даст вам данные немедленно.)

    Я думаю, что стоит хотя бы попробовать это простое решение.

    Как просто использовать

     void feedInputToOutput(InputStream in, OutputStream out) { IOUtils.copy(in, out); } 

    и сделать с этим?

    из библиотеки jacarta apache commons i / o, которая уже используется огромным количеством проектов, поэтому вы, вероятно, уже имеете банку в своем classе.

    Для полноты, гуава также имеет удобную утилиту для этого

     ByteStreams.copy(input, output); 

    Вы можете использовать круговой буфер:

    Код

     // 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()); 

    Зависимость от Maven

      org.ostermiller utils 1.07.00  

    Детали режима

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

    JDK 9 добавила InputStream#transferTo(OutputStream out) для этой функции.

    Асинхронный способ его достижения.

     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(); } 

    BUFFER_SIZE – размер патронов для чтения. Должно быть> 1kb и <10MB.

     private static final int BUFFER_SIZE = 2 * 1024 * 1024; private void copy(InputStream input, OutputStream output) throws IOException { try { byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead = input.read(buffer); while (bytesRead != -1) { output.write(buffer, 0, bytesRead); bytesRead = input.read(buffer); } //If needed, close streams. } finally { input.close(); output.close(); } } 

    Это версия Scala, которая является чистой и быстрой (без stackoverflow):

      import scala.annotation.tailrec import java.io._ implicit class InputStreamOps(in: InputStream) { def >(out: OutputStream): Unit = pipeTo(out) def pipeTo(out: OutputStream, bufferSize: Int = 1<<10): Unit = pipeTo(out, Array.ofDim[Byte](bufferSize)) @tailrec final def pipeTo(out: OutputStream, buffer: Array[Byte]): Unit = in.read(buffer) match { case n if n > 0 => out.write(buffer, 0, n) pipeTo(out, buffer) case _ => in.close() out.close() } } 

    Это позволяет использовать > символ, например inputstream > outputstream а также передавать пользовательские буферы / размеры.

    Использовать org.apache.commons.io.IOUtils

     InputStream inStream = new ... OutputStream outStream = new ... IOUtils.copy(inStream, outStream); 

    или copyLarge для размера> 2 ГБ

    Если вы работаете в функции, это функция, написанная на Scala, показывающая, как вы можете копировать входной stream в выходной stream, используя только vals (а не vars).

     def copyInputToOutputFunctional(inputStream: InputStream, outputStream: OutputStream,bufferSize: Int) { val buffer = new Array[Byte](bufferSize); def recurse() { val len = inputStream.read(buffer); if (len > 0) { outputStream.write(buffer.take(len)); recurse(); } } recurse(); } 

    Обратите внимание, что это не рекомендуется использовать в Java-приложении с небольшой доступной памятью, поскольку с помощью рекурсивной функции вы можете легко получить ошибку исключения переполнения стека

    Interesting Posts
    Давайте будем гением компьютера.