我正在开发一个接口,它将加密的字节流作为输入 - 可能是一个非常大的 - 产生或多或少相同格式的输出。
输入格式为:
{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
内部应该是什么样的?
答案 0 :(得分:1)
我不会创建一个类来处理输入和输出 - 一个类,一个责任。我想要两个过滤器流,一个用于输入/解密,另一个用于输出/加密:
InputStream decrypted = new DecryptingStream(inputStream, decryptionParameters);
...
OutputStream encrypted = new EncryptingStream(outputSream, encryptionOptions);
在第一次read()
调用之前,{@ 1}}首先write()
调用/写入信封之前,他们可能会使用惰性初始化机制来读取信封。您还可以在过滤器实现中使用Message或MessageEnvelope等类,但它们可能保留受包受保护的非API类。
处理对于仅在流上工作的解密/加密一无所知。在处理流处理输入和输出的过程中,您也可以同时使用两个流进行输入和输出。
答案 1 :(得分:0)
你可以在任意位置拆分身体吗?
如果是这样,我将有两个线程,输入线程和输出线程,并具有输出线程监视的并发队列的字符串。类似的东西:
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);
}
}
注意:这肯定不会按原样运作。只是一个设计的建议。欢迎有人编辑此内容。
答案 2 :(得分:0)
如果需要同时读写,则必须使用线程(不同的线程读写)或异步I / O(java.nio包)。使用来自不同线程的输入和输出流不是问题。
如果你想在java中创建一个流API,你通常应该提供InputStream用于读取和OutputStream用于写入。通过这种方式,可以将这些API传递给其他API,以便您可以将事物链接起来,从而使流一直作为流。
输入示例:
Message message = new Message(inputStream);
results = process(message.getInputStream());
输出示例:
Message message = new Message(outputStream);
writeContent(message.getOutputStream());
消息需要使用执行所需加密和解密的类来包装给定的流。
请注意,同时读取多条消息或同时写入多条消息也需要协议支持。您需要使同步正确。
答案 3 :(得分:0)
您应该在支持流加密的不同分组密码模式下检查Wikipedia article。不同的加密算法可能支持这些算法的子集。
缓冲流将允许您在循环中读取,加密/解密和写入。
演示ZipInputStream和ZipOutputStream的示例可以提供有关如何解决此问题的一些指导。见example。
答案 4 :(得分:0)
您需要的是使用密码流(CipherInputStream)。以下是example如何使用它。
答案 5 :(得分:0)
我同意Arne,数据处理器不应该知道加密,它只需要读取消息的解密主体,并写出结果,流过滤器应该负责加密。但是,由于这在逻辑上对同一条信息(消息)进行操作,我认为应打包在一个处理消息格式的类中,尽管加密/解密流确实独立于此
这是我对结构的想法,在某种程度上翻转架构,并将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输出; //这是发送消息的流 消息inputMessage = new消息(输入); 消息outputMessage = new Message(inputMessage.getEnvelope()); process(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.
}
}
这一切现在都是锁步,你不需要任何额外的线程。您也可以提前中止而无需处理整个消息(例如,如果输出流已关闭)。