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