0

我正在使用服务器-客户端模型与使用套接字编程的硬件板进行通信。

我使用“NetworkStream”类的“read()”方法从板上接收数据,该方法读取具有指定最大大小的缓冲区并返回缓冲区中有效数据的长度。我已经考虑了足够大的缓冲区的最大大小。

该板每 100 毫秒发送一组消息。每条消息都包含一个 2 字节的常量标头和可变数量的字节作为标头字节之后的数据。

问题是我没有收到一条一条的消息!相反,我收到的一个缓冲区可能包含 2 或 3 条消息,或者一条消息分散在两个缓冲区之间。

目前,我正在使用一个 DFA,它使用恒定的标头字节收集消息的内容(我们不知道消息的长度,我们只知道标头字节),但问题是数据字节可能随机包含标头字节! !

有没有任何有效的方法可以使用任何特定的流或类从缓冲区中收集每条消息的字节?我该如何克服这个问题?!

4

1 回答 1

1

您需要在您的消费者 DFA 和套接字客户端之间添加一个额外的缓冲区组件。

每当NetworkStream缓冲区组件中的数据可用时,将读取它并将其附加到自己的私有缓冲区,增加“可用字节”计数器。缓冲区组件至少需要向其用户公开以下功能:

  1. 一个BytesAvailable属性——返回计数器的值
  2. 一个PeekBytes(int count)方法——这将返回count缓冲区的第一个字节,如果至少有那么多可用,并且不修改计数器或缓冲区
  3. 一个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 将永远只处理整个消息。

于 2012-09-22T23:10:04.507 回答