【问题标题】:read specific number of bytes from NetworkStream从 NetworkStream 读取特定数量的字节
【发布时间】:2011-09-24 22:08:12
【问题描述】:

我正在尝试从网络流中读取一条已知长度的消息。 我有点期待NetworkStream.Read() 会等待返回,直到我给它的缓冲区数组已满。如果不是,那么ReadTimeout 属性的意义何在?

我用来测试我的理论的示例代码

public static void Main(string[] args)
{
    TcpListener listener = new TcpListener(IPAddress.Any, 10001);
    listener.Start();

    Console.WriteLine("Waiting for connection...");

    ThreadPool.QueueUserWorkItem(WriterThread);

    using (TcpClient client = listener.AcceptTcpClient())
    using (NetworkStream stream = client.GetStream())
    {
        Console.WriteLine("Connected. Waiting for data...");

        client.ReceiveTimeout = (int)new TimeSpan(0, 1, 0).TotalMilliseconds;
        stream.ReadTimeout = (int)new TimeSpan(0, 1, 0).TotalMilliseconds;

        byte[] buffer = new byte[1024];
        int bytesRead = stream.Read(buffer, 0, buffer.Length);

        Console.WriteLine("Got {0} bytes.", bytesRead);
    }

    listener.Stop();

    Console.WriteLine("Press any key to exit...");
    Console.ReadKey(true);
}

private static void WriterThread(object state)
{
    using (TcpClient client = new TcpClient())
    {
        client.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10001));
        using (NetworkStream stream = client.GetStream())
        {
            byte[] bytes = Encoding.UTF8.GetBytes("obviously less than 1024 bytes");
            Console.WriteLine("Sending {0} bytes...", bytes.Length);
            stream.Write(bytes, 0, bytes.Length);
            Thread.Sleep(new TimeSpan(0, 2, 0));
        }
    }
}

结果是:

Waiting for connection...
Sending 30 bytes...
Connected. Waiting for data...
Got 30 bytes.
Press any key to exit...

是否有一种标准方法来进行同步读取,仅在读取指定数量的字节时才返回?我确信自己编写一个并不太复杂,但是TcpClientNetworkStream 上的超时属性的存在表明它应该已经以这种方式工作了。

【问题讨论】:

  • 超过 1k 的代表仍然设法省略了一个最有用的标签。 head->desk
  • 我根本看不出这是一个与 C# 相关的问题。也不欣赏 asshattery。
  • 那么您使用的是什么编程语言?它确实看起来像 C#。

标签: sockets stream


【解决方案1】:

您可以保证是(其中之一):

  • 0 字节(流结束)
  • 至少 1 个字节(一些数据可用;并不意味着没有更多数据或已经可用)
  • 错误(超时等)

要读取指定数量的字节...循环:

int read = 0, offset = 0, toRead = ...
while(toRead > 0 && (read = stream.Read(buffer, offset, toRead)) > 0) {
    toRead -= read;
    offset += read;
}
if(toRead > 0) throw new EndOfStreamException();

【讨论】:

    【解决方案2】:

    TCP 是一种不保留应用程序消息边界的字节流协议。它根本无法以这种方式将字节“粘合”在一起。读取超时的目的是指定您希望读取阻塞多长时间。但只要能返回至少一个字节的数据,读操作就不会阻塞。

    如果您需要在循环中调用 read 直到您阅读完整的消息,请执行此操作。 TCP 层不在乎你认为什么是完整的消息,这不是它的工作。

    【讨论】:

    • 好吧,这是有道理的。嗯,不是真的,但它解释了我的期望是错误的。
    • 嗯,奇怪的是,如果写入线程在发送完整消息之前简单地退出(通过删除 Thread.Sleep()),则设置 ReadTimeout 绝对没有任何作用。
    • 我不太确定我是否关注您的评论。您是说即使设置了 ReadTimeout,读取也会永远阻塞?
    猜你喜欢
    • 1970-01-01
    • 2017-06-24
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多