我该如何处理不完整的数据包缓冲区?

5
我正在为一个通常以500字节或更少的字符串形式发送数据的服务器编写客户端。但是,数据偶尔会超过这个限制,一组数据可能包含200,000字节,而客户端无从得知(在初始化或重大事件时)。然而,我不想让每个客户端都运行一个50 MB的套接字缓冲区(如果可能的话)。
每组数据由空字符\0分隔。我应该使用什么样的结构来存储部分发送的数据集?
例如,服务器可能会发送ABCDEFGHIJKLMNOPQRSTUV\0WXYZ\0123!\0。我希望独立处理ABCDEFGHIJKLMNOPQRSTUV,WXYZ和123!。此外,服务器可以发送ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890LOL123HAHATHISISREALLYLONG而没有终止字符。我希望将该数据集存储在某个地方以供稍后附加和处理。
另外,我正在使用异步套接字方法(BeginSend、EndSend、BeginReceive、EndReceive)。如果有影响的话,请告诉我。
目前,我正在考虑使用List和StringBuilder。任何比较这两种情况的建议都将非常有帮助。
4个回答

4
从套接字读取数据并存入缓冲区。当您获得终止字符时,将其转换为消息并将其发送到代码的其他部分。
此外,请记住TCP是一个流,而不是数据包。因此,您永远不应该假设您会在单个读取中一次性获取所有内容。
至于缓冲区,您可能最多只需要每个连接一个。我建议从您合理地期望接收的最大大小开始,如果填满,则创建一个更大的缓冲区 - 典型的策略是在用完时将大小加倍,以避免过多的分配。
如果您有多个传入连接,您可能希望做一些像创建缓冲池之类的事情,并且在完成它们后仅返回“大”的缓冲区。

2

你可以使用List<byte>作为缓冲区,这样.NET框架会自动扩展它的大小。当你找到一个空终止符时,可以使用List.RemoveRange()从缓冲区中移除该消息并将其传递到上一层。

你可能希望添加一个检查,当长度超过一定限制时抛出异常,而不是等待客户端耗尽内存。

(这与Ben S的答案非常相似,但我认为字节列表在面对编码问题时比StringBuilder更加稳健。将字节解码为字符串最好在更高层次上完成,一旦你有了完整的消息。)


也许使用 MemoryStream 而不是 List<byte>?并且使用 stream.Seek(0, SeekOrigin.Begin) 代替 RemoveRange - Matthew Flaschen
这也是一种可能性。我想这取决于代码的结构。如果它在遇到空终止符时立即处理消息,那么寻找0就可以正常工作。然而,如果它首先读取所有挂起的套接字数据,然后查找空终止符,那么寻找0会丢失第一个消息之后的所有内容。我假设是后者。 - EMP

1
我会使用StringBuilder,一次读入一个字符,每当遇到空终止符时复制并清空生成器。

这正是我所想的,但我担心这会影响效率。 - Benjamin Manns
它不应该出现这种情况,因为它被设计成能够高效地处理追加任意字符串。 - Ben S

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接