我正在使用TPL Dataflow blocks来实现基于数据包的网络协议。该协议是固定的,我无法更改。通常会有许多小的数据包。
我有一个客户端组件连接到服务器并读取原始数据包。这些原始数据包随后被作为MemoryStreams发布到BufferBlock中,并在TransformBlock中解码成数据包结构体,具体取决于数据包类型/ID。
为了发送数据包,这个过程被反转,并使用另一条数据流块链。就我所知,所有这些都能很好地工作。
问题在于这些数据包可能会或可能不会被压缩和加密,这取决于服务器响应。我可以通过添加新的TransformBlocks来解决这个问题(以解压为例):
我有一个客户端组件连接到服务器并读取原始数据包。这些原始数据包随后被作为MemoryStreams发布到BufferBlock中,并在TransformBlock中解码成数据包结构体,具体取决于数据包类型/ID。
为了发送数据包,这个过程被反转,并使用另一条数据流块链。就我所知,所有这些都能很好地工作。
问题在于这些数据包可能会或可能不会被压缩和加密,这取决于服务器响应。我可以通过添加新的TransformBlocks来解决这个问题(以解压为例):
static TransformBlock<Stream, Stream> CreateDecompressorBlock(ProtocolContext context)
{
return new TransformBlock<Stream, Stream>(stream =>
{
if (!context.CompressionEnabled) return stream;
return new DeflateStream(stream, CompressionMode.Decompress);
}
}
然而,这对我来说似乎不是正确的方法。据我所知,DeflateStream(和CryptoStream)在读取数据时解码数据。这意味着,当我解码数据块内容时,数据已经被解码,而不是在TransformBlock中创建包装器Stream时解码。这似乎会规避Dataflow Blocks的优点。
因此,我想到另一个解决方案,即不返回DeflateStream/CryptoStream,而是将其读入另一个MemoryStream中:
static TransformBlock<Stream, Stream> CreateDecompressorBlock(ProtocolContext context)
{
return new TransformBlock<Stream, Stream>(stream =>
{
if (!context.CompressionEnabled) return stream;
using (var deflate = new DeflateStream(stream, CompressionMode.Decompress))
{
var ms = new MemoryStream();
deflate.CopyTo(ms);
return ms;
}
}
}
现在看来,这似乎是一种浪费内存的做法。
所以我的问题是,仅仅包装流并让稍后解码数据包内容的TransformBlock来完成工作是否足够,或者我应该使用更多的内存,然后实现更好的分离和可能的并行性呢?(虽然我不认为解码会成为瓶颈,因为网络才是瓶颈)。
或者有没有TPL Dataflow中可以更好地解决我的问题的模式?