您需要在您的消费者 DFA 和套接字客户端之间添加一个额外的缓冲区组件。
每当NetworkStream
缓冲区组件中的数据可用时,将读取它并将其附加到自己的私有缓冲区,增加“可用字节”计数器。缓冲区组件至少需要向其用户公开以下功能:
- 一个
BytesAvailable
属性——返回计数器的值
- 一个
PeekBytes(int count)
方法——这将返回count
缓冲区的第一个字节,如果至少有那么多可用,并且不修改计数器或缓冲区
- 一个
ReadBytes(int count)
方法——如上,但它递减计数器count
并删除从缓冲区读取的字节,以便后续PeekBytes
调用将永远不会再次读取它们
请记住,您不需要能够为任意高的count
参数提供服务;如果您可以count
随时接收最长的消息就足够了。
显然,缓冲区组件需要保留某种允许“环绕”的数据结构;您可能想研究一个循环(环形)缓冲区实现,或者您可以只使用两个固定大小的缓冲区,N
其中N
最长消息的长度是最长消息的长度,并在它们变满时从一个缓冲区切换到另一个缓冲区。您应该小心,以便在NetworkStream
缓冲区已满时停止从 中提取数据,并且仅在 DFA 调用ReadBytes
以释放一些缓冲区空间后继续提取。
每当你的 DFA 需要读取数据时,它会首先询问你的缓冲阶段它已经积累了多少数据,然后进行相应的处理。它看起来像这样:
if BytesAvailable < 2
return; // no header to read, cannot do anything
// peek at the header -- do not remove it from the buffer!
header = PeekBytes(2);
// calculate the full message length based on the header
// if this is not possible from just the header, you might want to do this
// iteratively, or you might want to change the header so that it is possible
length = X;
if BytesAvailable < X
return; // no full message to read, cannot continue
header = ReadBytes(2); // to remove it from the buffer
message = ReadBytes(X); // remove the whole message as well
这样,您的 DFA 将永远只处理整个消息。