如何监控套接字以获取新数据并处理该数据?

3
请原谅我对C#.Net的新手状态。如果这很明显而且我在文档中错过了它,那么请提供相关页面或示例代码的链接。
我正在开发一个应用程序,该应用程序将接受来自Java应用程序的TCP套接字连接。 (是的,该部分需要Java。这是Sun SPOT设备,而Java是唯一的选择。)Java应用程序将定期向套接字写入新数据,并且我的应用程序的工作是接收byte [],将其转换为字符串,处理数据(更新UI等),并可能将数据转发到运行类似C#.NET应用程序的另一台计算机上。
到目前为止,我已经完成了以下工作:现在,该应用程序在启动时会启动一个线程以打开套接字。 Java应用程序可以成功连接到套接字,因此它正在工作。我正在研究NetworkStream的beginRead方法以及dataAvailable,length和CanRead属性,但我不完全确定如何确定何时读取了一个数据包,通常约512字节但可能会有所不同。
如果Java应用程序向流写入数据或存在数据积压(Java应用程序将快速传递数据),如何确保我一次只读取一个数据包?如果Java应用程序在写入数据时将其空终止,这是否有帮助?足够吗?
最后,套接字只会接收一个连接,但我需要保持它开放,直到出现错误或连接终止。处理此方面的最优雅方式是什么?我认为每个数据包都关闭并重新打开不起作用,因为运行在Sun SPOT基站上的Java应用程序几乎是实时的。现在,当基站终止时,我的应用程序会死亡。
感谢您的阅读和提供的任何帮助。

TCP。谢谢,我会修改帖子。 - jxpx777
3个回答

5

"如果Java应用程序向流中写入数据或存在数据积压(Java应用程序将很快传递数据),我如何确保每次只读取一个数据包?"

请注意,不要假设您对哪些数据出现在哪个数据包中具有任何控制权。如果您尝试发送字节数据{ 'H','e','l','l','o' },则不能保证所有这些数据都将在单个数据包中发送。虽然这种情况极不可能发生,但仍有可能每个数据包只包含单个字节,因此您将在5个不同的事件中接收到全部五个字节。重点是不要以这种方式依赖数据包。相反,请定义自己的终止消息结束符,并简单地将所有传入数据投入某种字节缓冲区中,并编写另一个函数来检测是否存在任何这些终止符。如果存在,则读取到该终止符为止。例如,如果您从Java应用程序两次调用相应的发送方法并包含以下数据:

{ 'H', 'e', 'l', 'l', 'o', '\0' }
{ 'W', 'o', 'r', 'l', 'd', '\0' }

你的应用程序接收数据的准备工作应该像这样:

Server receives { 'H', 'e', 'l' }
Data stored in byte buffer { 'H', 'e', 'l' }
Check byte buffer for message terminator '\0'. None found. Buffer unchanged, no message processed.
Server receives { 'l', 'o', '\0', 'W' }
Data stored in byte buffer { 'H', 'e', 'l', 'l', 'o', '\0', 'W' }
Check byte buffer for message terminator '\0'. 1 found, extracted message { 'H', 'e', 'l', 'l', 'o' } and buffer updated { 'W' }

因此,虽然这并不完全回答了您最初的问题,但我认为它应该能够推动您朝着正确的方向前进。

您可能会遇到的一个问题是,有些字符可能只是数据而不是消息终止符。例如,许多文件包含数据\0,这些数据会破坏您的消息检测。通常处理这种情况的方法是为您的协议创建一个标头规范,并检测您是否正在等待标头(在这种情况下,查找\0将表示消息的结束),或者如果您正在等待一定量的数据(这可以由上次接收到的标头指定)。如果您不理解这个方法,或者认为您可能需要使用这个技术,请告诉我,我会在这个答案中添加更多信息。


这非常有帮助。我所知道的关于即将到来的数据是它不会跨越多行,因此\n或\0字符可以作为终止字符。这基本上是从SPOT传递到基站,然后传递到我的C#应用程序的传感器数据读数。IEEE地址,传感器信息。 - jxpx777
我认为这个应该是被接受的答案,尽管你做了一些不同的事情。 - Leandro López
@jxpx - 你需要进一步的澄清还是这个答案对你的问题可以接受? - Spencer Ruport
不,最终我选择了另一种方法。请参见我在此上方标记为已接受的答案。 - jxpx777

1

当你读取流数据时,需要一些标志/终止字符或已知的数据大小来确定何时停止读取并处理信息。空字符或换行符是常见的。另一种技术是使用固定大小的头部来指定正文的长度。

套接字将保持打开状态,直到你关闭它或另一端终止连接,在这种情况下,当你从套接字中读取数据时会出现错误,你应该处理它。NetworkStream在读取或写入操作期间远程端关闭套接字时抛出IOException异常。


有些东西需要通过检查每个字节来处理。如果您使用头部方法,可以读取固定数量的字节以获取头部信息。从中读取正文大小,然后再次调用具有正文固定大小的读取方法。这样,您就不需要检查所有字节了。 - grepsedawk
我的关于读取固定大小的评论适用于阻塞读取。 - grepsedawk

0
我们解决这个问题的方法是使用哨兵字符和固定宽度字段的组合。前两个字节是整个数据包的长度头。然后,我将数据包读入一个byte[]缓冲区,然后依靠我们自己的数据包结构来知道,例如,前两个字节应该被解释为单独的字段,然后字符串字段以\n字符(如果你在计分的话,是0x0A)终止。然后,长数据字段通过连续读取8个字节来处理等等。对我们来说,这似乎运作得非常好,但显然这只适用于那些能够控制套接字两端的情况,而不是只能控制其中一端的情况。希望这也能帮助其他人。

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