Почему TcpListener может пропускать УСТАНОВЛЕННЫЕ соединения? - PullRequest
2 голосов
/ 01 марта 2012

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

1 Ответ

1 голос
/ 01 марта 2012

Я на самом деле немного смущен примером кода - вопрос предполагает , что эти вопросы открыты достаточно долго, но код более типичен для очень коротких пакетов; для длительного соединения я бы ожидал увидеть здесь один из API-интерфейсов асинхронной синхронизации, а не API-интерфейс синхронизации.

Розетки, которые умирают без следа, очень распространены, особенно когда они распределены между несколькими промежуточными устройствами, которые все должны были бы обнаружить отключение. В частности, беспроводные сети иногда пытаются искусственно поддерживать работу сокетов, поскольку довольно часто кратковременно теряется беспроводное соединение, поскольку устройства не хотят, чтобы это каждый раз прерывало соединение.

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

В качестве примера - у меня здесь есть сервер веб-сокетов, который в теории обрабатывает как изящные отключения (через определенную последовательность, указывающую на закрытие), так и неуместное закрытие сокета (неожиданно разрывая соединение) - но 19k соединений, которые я видел за последний час или около того, 70 умерло, не поразив ни одного из них. Поэтому вместо этого я отслеживаю действия против (медленного) сердцебиения и убиваю их, если они не отвечают слишком долго.

Re timeout; вы можете попробовать ReceiveTimeout, но это поможет вам, только если вы не ожидаете больших пробелов в трафике.

...