我正在使用网络流在网络周围传递短字符串
现在,在接收方面我遇到了一个问题:
通常我会像这样阅读
在假设所有提供的方法都可能正常工作的代码中,看起来像这样:
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并没有真正实现,并且在调用时总会抛出异常 由于传入的数据长度不同,我不能硬编码预期的字节数(这也是魔数反模式的情况)。
问题:
如果我无法准确计算可用于读取的字节数,那么我如何正确地从流中读取,而不会在NetworkStream.Read中冒任何种类的例外?
修改:
虽然提供的答案会带来更好的整体代码,但我还是想分享我遇到的另一个选项:
TCPClient.Available给出了可读取的字节数。我知道必须有一种方法来计算自己收件箱中的字节数。
答案 0 :(得分:4)
无法保证连接一侧的Read
来电与来自另一方的Write
来电匹配。如果您正在处理可变长度的消息,则可以通过您向接收方提供此信息。
执行此操作的一种常见方法是首先计算您要发送的邮件的长度,然后首先发送该长度信息。然后在接收端,首先获取长度,然后知道要分配的缓冲区有多大。然后在循环中调用Read
,直到您读取正确的字节数。请注意,在原始代码中,您当前忽略来自Read
的返回值,它会告诉您实际读取了多少字节。在单个调用和返回中,即使您要求超过1个字节,也可以低至1。
另一种常见的方法是决定消息"格式" - 例如消息号1总是32字节长,具有 X 结构,消息号2长度为51字节,具有 Y 结构。使用这种方法,而不是在发送消息之前发送消息 length ,而是发送格式信息 - 首先发送"此处出现类型1和#34的消息;然后你发送消息。
另一种常见方法(如果适用)是使用某种形式的标记 - 如果您的消息永远不会包含值为0xff
的字节,那么您将扫描收到的字节,直到您收到一个0xff
字节,然后该字节之前的所有内容都是您想要接收的消息。
但是,无论你想做什么,无论是上述方法之一,还是别的什么,都可以你让你的发送方和接收方一起工作以允许接收器发现每条消息。
我忘了说但是改变一切的另一种方法是 - 如果你想交换消息,并且不想做任何上述摆弄,那么切换到在更高层次上工作的东西 - 例如WCF,或HTTP,或其他,这些系统已经处理消息框架,然后,您可以专注于如何处理您的消息。
答案 1 :(得分:1)
您可以使用StreamReader
将流读取到结尾
var streamReader = new StreamReader(someTcpClient.GetStream(), Encoding.ASCII);
string result = streamReader.ReadToEnd();