计算 TcpClient 通过 NetworkStream 传输的字节数 BinaryReader/BinaryWriter

Count bytes transmitted by TcpClient via NetworkStream BinaryReader/BinaryWriter

我正在使用围绕 TcpClient 构建的网络协议,使用 BinaryReader 从底层 NetworkStream 读取字节(相反,使用 BinaryWriter 写入) .

协议以 UTF-8 编码传输字符串,并调用 reader.ReadString() 从流中读取它们(使用 writer.Write(someStr) 写入)。

是否有一种简单的方法来确定从 NetworkStream 中读取(或写入)的字节数,而不必通过箍来计算传输的字符串的实际字节长度?

请注意,BinaryWriter.Write() 在字符串的实际字节之前写入一个 7 位编码的整数,这使得任何手动计算都变得更加复杂。

另请注意 NetworkStream 不支持 Position 属性,因为它抱怨无法 Seek

此外,我想避免将必须 copy/scan 数据的中介引入 reading/writing 的过程中,以免影响整个系统的性能。

是否有一种简单高级方法来计算通过网络接口的字节数,而无需手动考虑字符串的编码和长度?

您可以在网络流和计算字节数的 reader 之间插入自定义流。

没有必要为此复制数据。只需将经过的字节数添加到计数器即可。

对于那些对我如何实现字节计数流感到好奇的人,这里是它的全部荣耀(或臭名昭著,视情况而定):

using System;
using System.IO;

namespace Streams
{
    /// <summary>
    /// A wrapper around a <see cref="Stream"/> that keeps track of the number of bytes read and written.
    /// </summary>
    public class ByteCountingStream : Stream
    {
        private readonly Stream inner;

        private long totalBytesWritten;
        private long totalBytesRead;


        public ByteCountingStream(Stream inner)
        {
            this.inner = inner;
        }

        public override void Flush()
        {
            inner.Flush();
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotImplementedException();
        }

        public override void SetLength(long value)
        {
            throw new NotImplementedException();
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            int readBytes = inner.Read(buffer, offset, count);
            totalBytesRead += readBytes;
            return readBytes;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            inner.Write(buffer, offset, count);
            totalBytesWritten += count;
        }

        public override bool CanRead => true;
        public override bool CanSeek => false;
        public override bool CanWrite => true;

        public override long Length
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public override long Position { get; set; }

        public long TotalBytesWritten => totalBytesWritten;
        public long TotalBytesRead => totalBytesRead;
    }
}

该实现将缓冲区传递给基础流,因此实际上不涉及数据复制。