BinaryReader.ReadChars()的问题

Mik*_*e Q 7 .net c# binaryreader

我遇到了我认为BinaryReader.ReadChars()方法的问题.当我在原始套接字NetworkStream周围包装BinaryReader时偶尔会出现流损坏,其中正在读取的流不同步.所讨论的流包含二进制序列化协议中的消息.

我已将此跟踪到以下内容

  • 它只在读取unicode字符串时发生(使用Encoding.BigEndian编码)
  • 只有当有问题的字符串被分成两个tcp数据包时才会发生(使用wireshark确认)

我认为发生的事情如下(在下面的例子中)

  • 调用BinaryReader.ReadChars()要求它读取3个字符(字符串长度在字符串本身之前编码)
  • 第一个循环在内部请求从网络流中读取6个字节(3个剩余字符*2个字节/字符)
  • 网络流只有3个字节可用
  • 3个字节读入本地缓冲区
  • 缓冲区交给解码器
  • 解码器解码1个字符,并将另一个字节保留在它自己的内部缓冲区中
  • 第二个循环内部请求读取4个字节!(2个剩余字符*2个字节/字符)
  • 网络流有4个可用字节
  • 4个字节读入本地缓冲区
  • 缓冲区交给解码器
  • 解码器解码2个字符,并在内部保留剩余的第4个字节
  • 字符串解码完成
  • 序列化代码试图解组下一个项目并因为流损坏而呱呱叫.

    char[] buffer = new char[3];
    int charIndex = 0;
    
    Decoder decoder = Encoding.BigEndianUnicode.GetDecoder();
    
    // pretend 3 of the 6 bytes arrives in one packet
    byte[] b1 = new byte[] { 0, 83, 0 };
    int charsRead = decoder.GetChars(b1, 0, 3, buffer, charIndex);
    charIndex += charsRead;
    
    // pretend the remaining 3 bytes plus a final byte, for something unrelated,
    // arrive next
    byte[] b2 = new byte[] { 71, 0, 114, 3 };
    charsRead = decoder.GetChars(b2, 0, 4, buffer, charIndex);
    charIndex += charsRead;
    
    Run Code Online (Sandbox Code Playgroud)

我认为root是.NET代码中的一个错误,它使用charsRemaining*bytes/char每个循环来计算所需的剩余字节数.由于在解码器中隐藏了额外字节,因此该计算可以关闭一个,从而导致从输入流中消耗额外的字节.

这是有问题的.NET框架代码

    while (charsRemaining>0) { 
        // We really want to know what the minimum number of bytes per char 
        // is for our encoding.  Otherwise for UnicodeEncoding we'd have to
        // do ~1+log(n) reads to read n characters. 
        numBytes = charsRemaining;
        if (m_2BytesPerChar)
            numBytes <<= 1;

        numBytes = m_stream.Read(m_charBytes, 0, numBytes);
        if (numBytes==0) { 
            return (count - charsRemaining); 
        } 
        charsRead = m_decoder.GetChars(m_charBytes, 0, numBytes, buffer, index);

        charsRemaining -= charsRead;
        index+=charsRead;
    }
Run Code Online (Sandbox Code Playgroud)

我不完全确定这是一个错误还是仅仅是对API的滥用.为了解决这个问题,我只是计算自己需要的字节数,读取它们,然后通过相关的Encoding.GetString()运行byte [].然而,这不适用于像UTF-8这样的东西.

有兴趣听听人们对此的看法以及我是否做错了.也许它会为下一个人节省几个小时/几天的繁琐调试.

编辑:发布以连接连接跟踪项目

Jas*_*aty 3

我已经重现了您提到的问题BinaryReader.ReadChars

尽管开发人员在编写流和解码器等内容时始终需要考虑先行,但这似乎是一个相当重要的错误,BinaryReader因为该类旨在读取由各种类型的数据组成的数据结构。在这种情况下,我同意ReadChars在读取内容时应该更加保守,以避免丢失该字节。

直接使用的解决方法没有任何问题Decoder,毕竟这是ReadChars幕后的工作。

Unicode 是一个简单的例子。如果您考虑任意编码,那么当您传递字符计数而不是字节计数时,实际上没有通用的方法可以确保消耗正确的字节数(考虑不同长度的字符和涉及格式错误的输入的情况)。因此,避免BinaryReader.ReadChars读取特定字节数提供了更稳健、更通用的解决方案。

我建议您通过http://connect.microsoft.com/visualstudio将此问题提请 Microsoft 注意。