Почему TcpListener может пропускать УСТАНОВЛЕННЫЕ соединения?
У меня есть приложение, которое прослушивает сообщения от модема на 30 машинах. Я использовал TcpListener для реализации серверного кода, который выглядит следующим образом (обработка ошибок исключена):
...
listener.Start()
...
void
BeginAcceptTcpClient()
{
if(listener.Server.IsBound) {
listener.BeginAcceptTcpClient(TcpClientAccepted, null);
}
}
void
TcpClientAccepted(IAsyncResult ar)
{
var buffer = new byte[bufferSize];
BeginAcceptTcpClient();
using(var client = EndAcceptTcpClient(ar)) {
using(var stream = client.GetStream()) {
var count = 0;
while((count = stream.Read(buffer, total, bufferSize - total)) > 0) {
total += count;
}
}
DoSomething(buffer)
}
Я получаю сообщения правильно, моя проблема заключается в отключениях. Каждые 12 часов модемы сбрасываются и получают новый IP-адрес, но Сервер продолжает сохранять старые подключения активными (они отмечены как УСТАНОВЛЕННЫЕ в tcpview). Есть ли способ установить таймаут для старых подключений? Я думал, что при закрытии TcpClient TCP-соединение было закрыто (и это то, что происходит в моих локальных тестах), что я делаю неправильно?
1 ответ
Я на самом деле немного смущен примером кода - вопрос предполагает, что эти вопросы открыты достаточно долго, но код более типичен для очень коротких пакетов; для продолжительного соединения я бы ожидал увидеть здесь один из API-интерфейсов асинхронной синхронизации, а не API-интерфейс синхронизации.
Сокеты, которые умирают без следа, очень распространены, особенно когда они распределены между несколькими промежуточными устройствами, которые все должны были бы определить отключение. Беспроводные сети, в частности, иногда пытаются искусственно поддерживать розетки, поскольку довольно часто кратковременно теряется беспроводное соединение, поскольку устройства не хотят, чтобы это каждый раз прерывало соединение.
Таким образом, довольно часто для соединений используется какое-то сердцебиение, чтобы вы могли отслеживать, кто еще жив.
В качестве примера - у меня здесь есть сервер веб-сокетов, который теоретически обрабатывает как изящные выключения (с помощью определенной последовательности, указывающей на закрытие), так и неуместное закрытие сокета (неожиданно прерывает соединение) - но из 19k соединений, которые я видел в в последний час или около того, 70 умерли, не задев ни одного из них. Поэтому вместо этого я отслеживаю активность против (медленного) сердцебиения и убиваю его, если они не отвечают слишком долго.
Перерыв; Вы можете попробовать ReceiveTimeout
, но это поможет вам, только если вы не ожидаете больших пробелов в трафике.