NetworkStream.Length替代

时间:2014-05-12 06:24:56

标签: c# .net sockets networkstream

我正在使用网络流在网络周围传递短字符串 现在,在接收方面我遇到了一个问题:
通常我会像这样阅读

  1. 查看数据是否全部可用
  2. 获取可用数据
  3. 将许多字节读入缓冲区
  4. 将缓冲区内容转换为字符串。
  5. 在假设所有提供的方法都可能正常工作的代码中,看起来像这样:

    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给出了可读取的字节数。我知道必须有一种方法来计算自己收件箱中的字节数。

2 个答案:

答案 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();