如何解析在内存流中收到的数据?

时间:2013-11-06 03:13:29

标签: c# sockets tcpclient

我是新手使用套接字。我有一个非常基本的客户端发送请求,并等待响应。响应是一个流,但有两个部分。第一部分以ANS为前缀,是这种形式的一组键/值对:KEY:每一对的值在一个单独的行上。

响应的第二部分以RCT为前缀,这是需要直接发送到打印机的预格式化文本。

那么提取响应的两个部分的最佳方法是什么,在第一部分中,获取每个Key:Value对。我甚至可能都不需要它们,但我必须看看每一个,看看这些值是什么,然后决定如何处理它。

我目前正在将响应写到文本框中,只是为了理解它的作用,但现在我需要对数据做些什么。

以下是收到的数据样本:

ANS Result: Data Received                                                                
RCPRES:Q[81]
TML:123
OPP:
MRR:000000999999
<several dozen more KEY:Value pairs>
RCTNov 05 2013  04:03 pm      Trans# 123456

           <pre-formatted text>

2 个答案:

答案 0 :(得分:1)

将溪流视为带有门的传送带,其中包含物品。因此,当其他人将事情进一步增加时,你最终会在门后面有一个缓冲区。还有一个位于你的门所在位置的地方有一个传感器,它向另一个人发出信号,要求他停止将物品放在线上。你不必知道那个传感器有多远。 另一个人可能正在快速添加项目(直到他被信号通知传感器暂停)或者他可能会慢慢添加它们。

您可以通过调用.Peak()来检查门后备份的项目数。 您还可以通过调用.Read()

来读取(通过门)一行或多行

读取一个字节将是一个框,读取一个int将是4个框;因为int是4个字节长。 或者你可以读出一个(例如)4个整数的数组,这个数组是16个盒子/字节

(我认为如果你要求读取的数据多于缓冲区中的数据,那么它会阻塞(等待进一步上线的人发送更多的盒子,或者它抛出一个例外......您需要尝试并查看)

现在好了,您的数据。你很容易。每个键值对用新行分隔。 您可以做的是读取一个字节并将其转换为char并检查它是否为新行char,如果不将其添加到缓冲区以在最终找到时转换为字符串。

然而,这是混乱和低效的。 你可以做的是创建一个实现TextReader的阅读器,例如使用你的内存流StreamReader

StreamReader实现了一个ReadLine()方法,它将为您完成此任务。

现在好了,在while循环中,从socket / StreamReader逐行读取。 然后检查每一行,如果它是一个键值对或RCT thingy

如果是KVP,请将其添加到List中,或将其拆分为冒号并将其添加到Dictionary中;或类似的东西,以后再使用

如果是RCT,则调用ReadToEnd()将两个字符串(RCT转换为换行符和ReadToEnd)连接起来并将其传递给打印机。

您还可以在开始时对ANS进行说明。假设使用Read(Char[], Int32, Int32)重载。

答案 1 :(得分:1)

考虑到你已经将缓冲区完全加载到内存中,你正在使用缓冲区,你可以期待的最好的是有效的数组操作。据我所知,MemoryStream类只比内存中的一个字节数组Stream外观(当然还添加了适当的定位处理)。

您最好以最小的显着增量迭代流,因此假设您的示例文本是真实的,并且取决于新行是CR,LF还是CR + LF,它可能是一个或两个字节。迭代直到找到您期望的RCT前缀(假设在流中的其他地方找不到序列)应该允许您假设您仍在处理KV对并做出相应的响应。

一旦达到RCT前缀,您就需要切换到特定于您的实现的固定宽度处理方法。

就该系统的高级设计而言,我可能会建议一个捕获/状态对象,它能够表示来自消息的每个不同的可能KV对(假设固定值仍然具有关联的隐式密钥)。您需要至少2个不同的解析器来根据所需的格式处理请求;一个用于KEY:VALUE格式的显式KV对,另一个用于强格式化部分的隐式KV对。有了这些,只需迭代流字节并根据消息的“阶段”将消息的一部分委托给每个解析器。