我正在编写一个多线程.Net应用程序,其中许多调用者需要同时从单个Socket读取。
从套接字读取的数据被拆分为数据的记录/块 - 每个记录都定位在标头中由CallerID标识的特定调用者处,因此例如从套接字读取的字节流可能是沿线的的:
Header: CallerId = 1, Length = 5
Data: "Hello"
Header: CallerId = 2, Length = 6
Data: "Stack "
Header: CallerId = 1, Length = 7
Data: " World!"
Header: CallerId = 2, Length = 8
Data: "Overflow"
在这种情况下,调用者1读取的数据流应为“Hello World!”,而调用者2读取的数据流应为“Stack Overflow”。
Read
)和异步(BeginRead
)编程模型。 / LI>
caller1Stream.Read(12) // Hello world!
caller2Stream.Read(14) // Stack Overflow
我已经考虑过这样做,但我发现事情很快变得复杂,特别是;因为数据需要按顺序读取,因此在读取呼叫者数据时需要缓冲 - 这使得为给定呼叫者读取流的行为更加复杂:
当然这肯定是一个相当普遍的问题 - 是不是有一个.Net类可以使整个事情变得更简单? (请注意,我无法更改传输机制/协议)。有没有办法使用其中一个侦听器样式的类来执行上述操作?
如果没有,我该如何解决这些问题?
答案 0 :(得分:2)
基于你的帖子,我假设你使用TCP / IP,因为你指的是流媒体,但套接字也可以用于UDP无连接协议(以及其他)。 UDP非常简单,因为您只发送固定消息(无流媒体)。
无论如何,既然你指的是接收消息流,我必须假设你正在使用TCP / IP,如果你直接使用套接字,那么你正在寻找的是什么主要问题
TCP / IP是一个流解决方案,所以我在一端丢弃的东西从另一端出来,它总是按顺序排列,但不一定在一起。因此,如果你在一端写下“Hello World”,那么在阅读时你可能会得到“Hello World”,或“Hello”和“World”,甚至“H”“ello World”。关键是,没有办法调用read并期望接收整个消息。
我过去这样做的方法是只有一个中间线程(或者在我的情况下,我只是使用.net线程池),快速读取套接字,重新组装消息,然后传递将它们放到要处理的队列中。诀窍是重新组装,因为你不知道你收到了什么。在你的标题中说,消息长度是一个int32,即4个字节。当你调用read时,你甚至可能需要重新组装这个长度,因为你只收到了需要告诉长度的4个字节中的第一个字节。
听起来你的标题是固定的长度,所以基本上你需要做的,假设callerid和length是uint32的。尝试并读取8个字节,如果小于8,则放入缓冲区,直到我们读取8个字节。一旦我们读取了8个字节,取4个字节并获得长度,为消息的长度分配一个缓冲区。尝试并阅读,直到我们填充缓冲区,一旦我们有,将其放入特定callerid的队列,并发信号通知线程有新消息,以防它正在休眠。然后拿掉剩下的东西,然后重新开始,或等待更多数据。
我过去曾成功使用过它,但它增加了相对较少的开销。
答案 1 :(得分:0)
我不确定你有多少自由选择替代品,但这里有两个: