.NET Tcp Stream не работает, если простаивает более трех минут - PullRequest
0 голосов
/ 28 сентября 2011

У меня есть система сбора данных, которая передает данные со сборного компьютера (сервера) на компьютер печати (клиент) по TCP-соединению.Код работает нормально при первом запуске коллекции.Код продолжает нормально работать при последующих запусках, если система не остается бездействующей более трех минут.Если система остается бездействующей более трех минут, передача зависает в течение первых 12 секунд или около того (достаточно долго, чтобы вызвать переполнение буферов сбора).

В начале каждой коллекции клиент зацикливается на 30 секунд, где он проверяет каждые 1 мс, чтобы определить, является ли _clientStream.DataAvailable = true.Этот цикл выглядит примерно так (некоторый код проверки ошибок удален):

    public bool WaitForData(int maxWaitInMs)
    {
       DateTime start_time = DateTime.Now;

        while (!_clientStream.DataAvailable )
        {
            Thread.Sleep(DATA_WAIT_DELAY); //1 ms
            TimeSpan elapsed_time = DateTime.Now - start_time;
            if (elapsed_time.TotalMilliseconds > maxWaitInMs)
            {
                return false;
            }
        }
        return true;
    }

На стороне сервера просто выполняется запись данных фиксированной длины

 _dataTcpServer.SendData(packet_buffer, OFFSET, packet.Size());

Когда возникает проблема,По отладчику я могу сказать, что сервер вызывает SendData один раз, возвращает, получает следующий пакет данных, снова вызывает метод send, а затем в течение примерно 12 секунд зависает при вызове SendData.Тем временем клиент никогда не увидит, что DataAvailable сбывается, пока не пройдет 12 секунд.Время ожидания отправки оставлено по умолчанию, поэтому оно должно быть бесконечным.Кажется, что 12-секундный интервал в некоторой степени связан с количеством отправляемых данных.

Одна вещь, которую я сделал по-другому в этой системе, заключалась в том, что вместо создания TcpClient при запуске клиентского приложения я запускаю TcpClient, когда клиенту необходимо подключиться.При отключении я распоряжаюсь потоком, полученным через TcpCLient.GetStream, и закрываю TcpClient.

Я просто надеюсь на некоторое понимание того, почему бездействие в течение трех минут имеет такой эффект (обе системы работают под управлением XP).

РЕДАКТИРОВАТЬ - Проблема решена, но понимание становится неуловимым

На сервере я использовал отдельный поток, который использовал TcpListener.AcceptTcpClient () для подключения клиента.AcceptTcpClient () возвращает объект TcpClient.Я бы периодически проверял это свойство IsConnected в TcpClient, чтобы знать, отключился ли клиент (т. Е. Измерение завершено), а затем снова ожидал бы AcceptTcpClient () и ждал начала следующего измерения.Проблема заключалась в том, что, хотя TcpClient клиента был отключен, TcpClient.IsConnected сервера всегда возвращал значение true.

Я решил проблему, отправив клиенту сообщение (не через TCP) на сервер, а затем сервер принудительно отключил его.Теперь все работает, но я убежден, что я не использую этот API должным образом.Хотя я вижу методы асинхронного принятия, я не вижу, как сервер должен выяснять, когда клиент отключается, и не понимаю, почему свойство TcpClient.IsConnected сервера будет возвращать true, если больше нетдействительное соединение.

Также я опоздал, заметив свойство ExclusiveAddressUse, поэтому никогда не устанавливал его в значение true.Система действовала так, как если бы через несколько минут было установлено другое клиентское соединение, то же самое соединение использовалось повторно, и сервер мог отправлять данные клиенту (то есть, как будто клиент никогда не отключался).Если с момента разъединения прошло более трех минут, новое клиентское соединение было принято (хотя, насколько я могу судить, мой код никогда не возвращался в строку AcceptTcpClient ()), но это больше не было то же соединение, которым был серверотправка на.

Ответы [ 2 ]

1 голос
/ 29 сентября 2011

Хотя я все еще не понимаю, почему мой клиент мог подключиться, когда мой сервер не находился в состоянии ожидания на AcceptTcpClient, я думаю, что я понимаю, почему Connected возвращает true, даже если клиент отключен.Я покопался в документации по Socket на MSDN и увидел следующее:

Значение свойства Connected отражает состояние соединения на момент последней операции.Если вам необходимо определить текущее состояние соединения, сделайте неблокирующий нулевой байт отправляющий вызов.

Поскольку клиент знает, что нужно выйти, поскольку сервер прекратил отправку данных при последней отправке перед клиентомуход был успешным.Я думаю, что Connected - это ужасное имя для этого свойства.Это должен быть WasConnected или WasConnectedAtLastSend, в то время как более многословный это избавило бы меня от душевных болей (и поэтому было бы быстрее читать документы MSDN).

1 голос
/ 28 сентября 2011

Thread.Sleep это ЗЛО при работе с IO. Вместо этого используйте socket.BeginReceive и возвращайтесь, если он все еще не работает.

...