【问题标题】:Count bytes transmitted by TcpClient via NetworkStream BinaryReader/BinaryWriter统计 TcpClient 通过 NetworkStream BinaryReader/BinaryWriter 传输的字节数
【发布时间】:2016-03-20 08:11:52
【问题描述】:

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

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

是否有一种简单的方法可以确定从 NetworkStream 读取(或写入)的字节数,而无需跳过循环来计算传输字符串的实际字节长度?

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

还要注意NetworkStream 不支持Position 属性,因为它抱怨不能Seek

另外,为了不影响整个系统的性能,我想避免在读/写过程中引入必须复制/扫描数据的中介。

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

【问题讨论】:

  • 你想达到什么目的?您可以在网络流和计算字节数的阅读器之间插入自定义流。
  • @usr 我只需要知道读取/写入的总字节数 - 用于报告目的。底层协议栈中的某些东西必须知道发送/接收的字节数...我想以最少的麻烦获得该信息。

标签: c# network-programming tcpclient networkstream binaryreader


【解决方案1】:

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

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

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

【讨论】:

  • Length 看起来坏了。这不总是返回 0 吗?应该扔。
  • 位置也是。我几乎忽略了新的简洁 6.0 语法。需要习惯这一点。另外,我认为如果不处置该类是非常危险的。
【解决方案2】:

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

不需要复制数据来做到这一点。只需将经过的字节数添加到计数器即可。

【讨论】:

  • 你能画出一个例子来说明如何做到这一点吗?
  • 有什么具体问题吗?从 Stream 派生并以这种方式包装另一个流实例。
  • 不需要缓冲数据吗?我不想让事情慢下来。
  • 我已经说过不会有缓冲了。如果您认为这不是真的,请提供缓冲的原因。也许您应该开始使用流实现,以便了解它的外观。例如,在 Read 方法中,您将传入的缓冲区传递给内部流。
  • 我说我想要一个简单的方法。虽然创建自定义流并不可怕 - 你是对的,它比我想象的要容易:-) - 确保它用于以前使用 NetworkStream 的所有地方被证明是一个主要的麻烦。不是我正在寻找的 easy 解决方案,但它有效,所以我会接受你的回答。谢谢。
猜你喜欢
  • 2018-08-21
  • 2012-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-27
相关资源
最近更新 更多