настройка NetworkStream.ReceiveTimeout не вызывает исключение - PullRequest
0 голосов
/ 25 сентября 2011

Это продолжение вопроса this . Я новичок в сетевом программировании, поэтому я просто пишу небольшие примеры, чтобы понять, но немного пытаюсь объяснить результаты.

Кажется, настройка 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() продолжает возвращать ноль, но исключение не выдается.

Это нормально? Если да, как я могу справиться с ненормальным отключением клиента?

1 Ответ

3 голосов
/ 25 сентября 2011

Да, это звучит нормально.Нет тайм-аута при получении или чтении, потому что клиент отключился.Это означает, что больше нет данных для чтения, и поток сразу же вернет 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, когда больше данных не будет получено, что в этом случае означает, что соединение закрыто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...