Почему 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, но это поможет вам, только если вы не ожидаете больших пробелов в трафике.

Другие вопросы по тегам