Объект данных Java для двунаправленного ввода-вывода - PullRequest
3 голосов
/ 12 декабря 2008

Я разрабатываю интерфейс, который принимает в качестве входных данных зашифрованный поток байтов - вероятно, очень большой , - который генерирует выходные данные более или менее того же формата.

Формат ввода следующий:

{N byte envelope}
    - encryption key IDs &c.
{X byte encrypted body}

Формат вывода такой же.

Вот обычный вариант использования (конечно, с сильным псевдокодированием):

Message incomingMessage = new Message (inputStream);

ProcessingResults results = process (incomingMessage);

MessageEnvelope messageEnvelope = new MessageEnvelope ();
// set message encryption options &c. ...

Message outgoingMessage = new Message ();
outgoingMessage.setEnvelope (messageEnvelope);

writeProcessingResults (results, message);

message.writeToOutput (outputStream);

Мне кажется, имеет смысл использовать один и тот же объект для инкапсуляции этого поведения, но я немного растерялся относительно того, как мне поступить. Загружать все зашифрованное тело за раз непрактично; Мне нужно иметь возможность потоковой передачи (поэтому я буду использовать какой-то фильтр входного потока для его расшифровки), но в то же время мне нужно иметь возможность записывать новые экземпляры этого объекта. Какой хороший подход к созданию этой работы? Как должен Message выглядеть внутренне?

Ответы [ 6 ]

1 голос
/ 20 января 2009

Я не буду создавать один класс для обработки входных и выходных данных - один класс, одна ответственность. Я хотел бы два потока фильтра, один для ввода / расшифровки и один для вывода / шифрования:

InputStream decrypted = new DecryptingStream(inputStream, decryptionParameters);
...
OutputStream encrypted = new EncryptingStream(outputSream, encryptionOptions);

У них может быть что-то вроде ленивого механизма инициализации, читающего конверт перед первым read() вызовом / записью конверта перед первым write() вызовом. Вы также используете классы, такие как Message или MessageEnvelope, в реализациях фильтра, но они могут оставаться защищенными пакетами, не являющимися классами API.

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

0 голосов
/ 21 января 2009

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

Вот моя идея структуры, несколько перевернувшей архитектуру и переместив класс Message за пределы потоков шифрования:

class Message {
  InputStream input;
  Envelope envelope;

  public Message(InputStream input) {
    assert input != null;
    this.input = input;
  }

  public Message(Envelope envelope) {
    assert envelope != null;
    this.envelope = envelope;
  }

  public Envelope getEnvelope() {
    if (envelope == null && input != null) {
      // Read envelope from beginning of stream
      envelope = new Envelope(input);
    }
    return envelope
  }

  public InputStream read() {
    assert input != null

    // Initialise the decryption stream
    return new DecryptingStream(input, getEnvelope().getEncryptionParameters());
  }

  public OutputStream write(OutputStream output) {
    // Write envelope header to output stream
    getEnvelope().write(output);

    // Initialise the encryption
    return new EncryptingStream(output, getEnvelope().getEncryptionParameters());
  }
}

Теперь вы можете использовать его, создав новое сообщение для ввода и одно для вывода: OutputStream output; // Это поток для отправки сообщения Сообщение inputMessage = новое сообщение (вход); Сообщение outputMessage = новое сообщение (inputMessage.getEnvelope ()); процесс (inputMessage.read (), outputMessage.write (output));

Теперь метод процесса просто должен прочитать порции данных в соответствии с требованиями ввода и записать результаты в вывод:

public void process(InputStream input, OutputStream output) {
  byte[] buffer = new byte[1024];
  int read;
  while ((read = input.read(buffer) > 0) {
    // Process buffer, writing to output as you go.
  }
}

Теперь все это работает в режиме реального времени, и вам не нужны никакие дополнительные потоки. Вы также можете прервать работу раньше, не обрабатывая все сообщение (например, если выходной поток закрыт).

0 голосов
/ 19 января 2009

Вам нужно использовать Cipher Streams ( CipherInputStream ). Вот пример того, как его использовать.

0 голосов
/ 08 января 2009

Вам следует проверить Статья в Википедии о различных режимах блочного шифрования, поддерживающих шифрование потоков. Различные алгоритмы шифрования могут поддерживать их подмножество.

Буферизованные потоки позволят вам читать, шифровать / дешифровать и записывать в цикле.

Примеры, демонстрирующие ZipInputStream и ZipOutputStream, могут дать некоторые рекомендации о том, как вы можете решить эту проблему. См. пример .

0 голосов
/ 02 января 2009

Если вам нужно читать и писать одновременно, вы должны либо использовать потоки (чтение и запись разных потоков), либо асинхронный ввод-вывод (пакет java.nio). Использование потоков ввода и вывода из разных потоков не является проблемой.

Если вы хотите создать потоковый API в java, вы обычно должны предоставить InputStream для чтения и OutputStream для записи. Таким образом, они могут быть переданы для других API, чтобы вы могли связывать вещи в цепочку и получать потоки в виде потоков.

Пример ввода:

Message message = new Message(inputStream);
results = process(message.getInputStream());

Пример вывода:

Message message = new Message(outputStream);
writeContent(message.getOutputStream());

Сообщение должно обернуть данные потоки классами, которые выполняют необходимое шифрование и дешифрование.

Обратите внимание, что для чтения нескольких сообщений одновременно или написания нескольких сообщений одновременно потребуется поддержка протокола. Вам нужно правильно настроить синхронизацию.

0 голосов
/ 12 декабря 2008

Можете ли вы разделить тело в произвольных местах?

Если это так, у меня будет два потока, входной поток и выходной поток, и параллельная очередь строк, которую отслеживает выходной поток. Что-то вроде:

ConcurrentLinkedQueue<String> outputQueue = new ConcurrentLinkedQueue<String>();
...

private void readInput(Stream stream) {
    String str;
    while ((str = stream.readLine()) != null) {
       outputQueue.put(processStream(str));
    }
}

private String processStream(String input) {
    // do something
    return output;
}

private void writeOutput(Stream out) {
    while (true) {
        while (outputQueue.peek() == null) {
            sleep(100);
        }

        String msg = outputQueue.poll();
        out.write(msg);
    }
}

Примечание: это точно не будет работать как есть. Просто предложение дизайна. Кто-то может редактировать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...