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

本文关键字:传输 字节数 BinaryWriter 通过 NetworkStream BinaryReader TcpClient | 更新日期: 2023-09-27 18:26:42

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

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

有没有一种简单的方法可以确定从NetworkStream读取(或写入)的字节数,而不必跳过重重关卡来计算传输字符串的实际字节长度?

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

还要注意,NetworkStream不支持Position属性,因为它抱怨无法使用Seek

此外,我希望避免在读/写过程中引入必须复制/扫描数据的中介机构,以免影响整个系统的性能。

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

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

对于那些好奇我是如何实现字节计数流的人来说,这里是它的荣耀(或耻辱,视情况而定):

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;
    }
}

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

您可以在networkstream和计算字节数的读取器之间插入一个自定义流。

这样做不需要复制数据。只需将传递给计数器的字节数相加即可。