Socket.SendAsync не обнаруживает мертвое TCP-соединение - PullRequest
1 голос
/ 18 августа 2010

У меня проблема с методом Socket.SendAsync, не обнаружившим оборванное TCP-соединение.В моем клиент-серверном приложении сервер регулярно отправляет тактовые импульсы подключенным клиентам.

Проблема, с которой я сталкиваюсь, заключается в том, что даже если клиент может быть мертвым, обратные вызовы из метода SendAsync указывают «SocketError.Success», а свойство Socket.Connected имеет значение true, хотя клиент недольше "живой".Таким образом, на сервер похоже, что данные пульса были отправлены правильно, а клиент все еще жив.

Я вижу эту проблему каждый раз, когда клиентский ПК переводится в спящий режим / режим гибернации или, например, когда клиент работает в экземпляре VMWare, и этот экземпляр приостанавливается.Я не вижу этой проблемы, когда клиент закрывает приложение, убивает его из диспетчера задач и т. Д.

    internal void InternalSendAsync(ByteDataChunk chunk)
    {
        asyncSendArgs.SetBuffer(chunk.Buffer, 0, chunk.Offset);
        asyncSendArgs.UserToken = chunk;
        Socket.SendAsync(asyncSendArgs);
    }

    private void SendCompleted(object sender, SocketAsyncEventArgs args)
    {
        if (args.SocketError != SocketError.Success || !Socket.Connected)
        {
            InternalDisconnect(args.SocketError);
            return;
        }

        // all is good & do some other stuff
    }

Кто-нибудь знает, что здесь происходит, и почему метод SendCompleted не возвращает ошибку SocketErrorхотя клиент давно мертв (у меня сервер работал несколько часов назад, а мертвый сокет никогда не обнаруживался)?

Спасибо,

Том

Ответы [ 4 ]

3 голосов
/ 19 августа 2010

С MSDN :

Обратите внимание, что успешное завершение метода SendAsync не означает, что данные были успешно доставлены.

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

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

0 голосов
/ 20 августа 2010

Вы использовали Wireshark или подобное, чтобы увидеть, что происходит в сети? Можно подумать, что если подсистема TCP на клиенте не подтверждает пакеты, то должна быть ошибка сокета. Может быть, клиент держит порт открытым и подтверждает пакет (ы). Если это так, то вы можете попытаться решить это на клиенте или сделать то, что сказал Николай.

0 голосов
/ 19 августа 2010

Игнорировать свойство Socket.Connected;это в значительной степени бесполезно.В вашем примере кода вы предполагаете, что все в порядке, если либо Socket.Connected - true, либо не было кода ошибки.Первое, что я хотел бы сделать, это удалить часть Socket.Connected.

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

Передача должна прекратиться несколько раз с экспоненциальным возвратом.Таким образом, требуется определенное время, чтобы определить, когда исчезает другая сторона (в случае выхода из программы ОС немедленно ответит, что соединение больше не жизнеспособно).Это не должно быть где-нибудь около часов, хотя;самое большее несколько минут (при условии медленного подключения к сети для начала).Мои сокеты регулярно обнаруживают потерянные соединения в течение секунды или около того.

0 голосов
/ 19 августа 2010

Сердцебиение действительно отправлено?Я подозреваю, что алгоритм Naggle .Вытащите wireshark и проверьте, что течет по проводу.Вы можете отключить Nagle с помощью SocketOptionName.NoDelay.Начиная с MSDN :

Успешное завершение метода BeginSend означает, что в базовой системе есть место для буферизации ваших данных для отправки по сети. Если для вашего приложения важно немедленно отправить каждый байт на удаленный хост, вы можете использовать SetSocketOption для включения SocketOptionName.NoDelay. Для получения дополнительной информации о буферизации для повышения эффективности сети см. Алгоритм Nagle вMSDN.
...