设置 NetworkStream.ReceiveTimeout 不触发异常

发布于 2024-12-06 03:29:15 字数 1747 浏览 0 评论 0原文

这是这个问题的延续。我是网络编程的新手,所以我只是编写一些小示例来获得理解,但在解释结果方面有些困难。

当应该发送数据的客户端在发送所有预期数据之前关闭时,设置 NetworkStream.ReceiveTimeout 似乎无法正常工作。

以下是示例代码:

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

    ThreadPool.QueueUserWorkItem(WriterThread);

    using (TcpClient client = listener.AcceptTcpClient())
    using (NetworkStream stream = client.GetStream())
    {
        client.ReceiveTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
        stream.ReadTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
        ReceiveMessage(stream, 1024);
    }

    listener.Stop();

    Console.WriteLine("Done.");
    Console.ReadKey(true);
}


private static void WriterThread(object state)
{
    using (TcpClient client = new TcpClient())
    {
        client.Connect(new IPEndPoint(IPAddress.Loopback, 10001));
        using (NetworkStream stream = client.GetStream())
        {
            byte[] bytes = Encoding.ASCII.GetBytes("obviously less than 1024 bytes");
            stream.Write(bytes, 0, bytes.Length);

            Thread.Sleep(10000); // comment out 
        }
    }
}


private static byte[] ReceiveMessage(Stream stream, int length)
{
    byte[] buffer = new byte[length];
    int bufferFill = 0;

    while (true)
    {
        bufferFill += stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
        if (buffer.Length == bufferFill)
            return buffer;

        Thread.Sleep(100);
    }
}

此版本可以正常工作,在 stream.Read() 调用上触发异常。但是,如果我注释掉 Thread.Sleep(10000),客户端会关闭连接,但侦听器无法识别它。主线程卡在 while(true) 循环内。 stream.Read() 不断返回零,但没有抛出异常。

这是正常的吗?如果是这样,我该如何处理异常的客户端断开连接?

This is a continuation of the this question. I am new to network programming, so I am just writing small sample stuff to gain understanding, but somewhat struggling with explaining results.

It seems setting NetworkStream.ReceiveTimeout is not working correctly when client that was supposed to be sending data simply closes before sending all the expected data.

Here is the sample code:

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

    ThreadPool.QueueUserWorkItem(WriterThread);

    using (TcpClient client = listener.AcceptTcpClient())
    using (NetworkStream stream = client.GetStream())
    {
        client.ReceiveTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
        stream.ReadTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
        ReceiveMessage(stream, 1024);
    }

    listener.Stop();

    Console.WriteLine("Done.");
    Console.ReadKey(true);
}


private static void WriterThread(object state)
{
    using (TcpClient client = new TcpClient())
    {
        client.Connect(new IPEndPoint(IPAddress.Loopback, 10001));
        using (NetworkStream stream = client.GetStream())
        {
            byte[] bytes = Encoding.ASCII.GetBytes("obviously less than 1024 bytes");
            stream.Write(bytes, 0, bytes.Length);

            Thread.Sleep(10000); // comment out 
        }
    }
}


private static byte[] ReceiveMessage(Stream stream, int length)
{
    byte[] buffer = new byte[length];
    int bufferFill = 0;

    while (true)
    {
        bufferFill += stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
        if (buffer.Length == bufferFill)
            return buffer;

        Thread.Sleep(100);
    }
}

This version works correctly triggering exception on the stream.Read() call. However If I comment out Thread.Sleep(10000), the client closes connection, but listener fails to recognize it. Main thread gets stuck inside the while(true) loop. The stream.Read() keeps returning zero, but no exception thrown.

Is this normal? If so how am I expected to handle abnormal client disconnections?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一杯敬自由 2024-12-13 03:29:15

是的,这听起来很正常。由于客户端已断开连接,因此不会出现接收或读取超时。这意味着没有更多数据可供读取,并且流将立即返回 0,如记录的那样。

我会将您的 ReceiveMessage 方法修改为如下所示:

private static byte[] ReceiveMessage(Stream stream, int length)
{
   byte[] buffer = new byte[length];
   int bufferFill = 0;

   while (true)
   {
      int bytesRead = stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
      if (bytesRead == 0)
         throw new Exception("No more data available.");
      bufferFill += bytesRead;
      if (buffer.Length == bufferFill)
         return buffer;

      Thread.Sleep(100);
   }
}

显然,如果在我们收到所有预期字节之前stream.Read() 调用返回 0,则一定存在某种形式的断开连接或类似情况。无论哪种方式,我们都不会从流中获取更多数据。

编辑: Stream 类没有“消息”的概念。如果缓冲区中尚无数据,则 Read 方法将阻塞,直到有更多数据可用为止。然而,当无法接收更多数据时,它将返回 0,在这种情况下意味着连接已关闭。

Yes, this sounds normal. There is no receive- or read timeout because the client has disconnected. This means that no more data is available for reading and the stream will return 0 immediately just as documented.

I would modify your ReceiveMessage method to something like the following:

private static byte[] ReceiveMessage(Stream stream, int length)
{
   byte[] buffer = new byte[length];
   int bufferFill = 0;

   while (true)
   {
      int bytesRead = stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
      if (bytesRead == 0)
         throw new Exception("No more data available.");
      bufferFill += bytesRead;
      if (buffer.Length == bufferFill)
         return buffer;

      Thread.Sleep(100);
   }
}

Clearly if the stream.Read() call returns 0 before we have received all the expected bytes there must have been some form of disconnection or similar. Either way we will never get any more data from the stream.

Edit: The Stream class has no notion of a "message". The Read method blocks until more data becomes available if none is already in the buffer. It will however return 0 when no more data can be received, which in this case means the connection is closed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文