我正在使用networkstream在网络上传递短字符串。
现在,在接收方,我遇到了一个问题:
通常我会这样阅读
在假定所有提供的方法都可以正常工作的代码中,看起来像这样:
NetworkStream stream = someTcpClient.GetStream();
while(!stream.DataAvailable)
;
byte[] bufferByte;
stream.Read(bufferByte, 0, stream.Lenght);
AsciiEncoding enc = new AsciiEncoding();
string result = enc.GetString(bufferByte);
但是,MSDN表示NetworkStream.Length并未真正实现,并且在被调用时始终会引发Exception。
由于传入的数据长度不同,因此我无法对期望的字节数进行硬编码(这也是魔数(Magic Number)反模式的情况)。
问题:
如果我无法准确计数可读取的字节数,那么如何正确地从流中读取数据,而又不冒NetworkStream.Read内的各种异常的风险?
编辑:
尽管提供的答案可以带来更好的总体代码,但我仍然想分享我遇到的另一个选择:
TCPClient.Available给出可读取的字节。我知道必须有一种方法来计算自己收件箱中的字节数。
最佳答案
无法保证在连接的一侧对Read
的调用将与另一侧对Write
的调用匹配1-1。如果要处理可变长度的消息,则由决定由来向接收方提供此信息。
一种常见的方法是首先确定您要发送的消息的长度,然后再发送该长度信息。在接收端,您首先要获得长度,然后知道要分配多大的缓冲区。然后,您可以循环调用Read
,直到读取了正确的字节数为止。请注意,在您的原始代码中,您当前忽略了Read
的返回值,该值告诉您实际读取了多少个字节。在一次调用和返回中,即使您要求的字节数超过1个,该值也可能低至1。
另一种常见的方式是决定消息的“格式”,例如消息号1始终为32字节,具有X结构,消息号2则为51字节,具有Y结构。使用这种方法,而不是在发送消息之前先发送消息长度,而是发送格式信息,而是先发送“这里是类型为1的消息”,然后再发送消息。
如果适用的话,另一种常见的方式是使用某种形式的哨兵-如果您的消息将永远不会包含一个带有0xff
值的字节,那么您将扫描接收到的字节,直到收到一个0xff
字节为止,然后再扫描该字节之前的所有内容。字节是您想要接收的消息。
但是,无论您想做什么,无论是上述方法之一还是其他方法,都必须由您的发送方和接收方共同努力以允许接收方发现每条消息。
我忘了说了,但是改变周围一切的另一种方法是-如果您想交换消息,并且不想做上述任何事情,然后切换到更高级的东西-例如WCF或HTTP或其他东西,这些系统已经在处理消息帧,然后您可以集中精力处理消息。
关于c# - NetworkStream.Length替代,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23602323/