Обработка пользовательских тайм-аутов на TCP-сервере в C # - PullRequest
3 голосов
/ 01 декабря 2011

Я пишу простой C # tcp сервер сообщений, который должен реагировать на тот факт, что подключенный клиент молчал последние TimeSpan timeout. Другими словами

  1. Клиент А подключается.
  2. Клиент А отправляет вещи.
  3. Сервер отвечает клиенту A.
  4. Клиент B подключается.
  5. timeout время проходит без отправки клиентом А
  6. Сервер отправляет "ping" (не как при сетевой проверке, а как в сообщении, SendPing) на A.
  7. Клиент Б отправляет вещи.
  8. Сервер отвечает.
  9. pingTimeout время после того, как пинг был отправлен A, соединение с A разорвано, а клиент удален.
  10. То же самое происходит, если B слишком долго молчит.

Простой рассказ. Если в timeout не было слышно ни слова из client[n], отправьте пинг. Если на ping получен ответ, просто обновите client[n].LastReceivedTime, однако, если client[n] не отвечает в течение pingTimeout, разорвите соединение.

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

while(true) {
    foreach(var c in clients) {
        if(DateTime.Now.Subtract(c.LastReceivedTime) >= timeout && !c.WaitingPing)
            c.SendPing();
        else if(DateTime.Now.Subtract(c.LastReceivedTime) >= timeout + pingTimeout && c.WaitingPing)
            c.Drop();
    }
}

будет просто жарить процессор и будет совсем нехорошо. Есть ли хороший простой алгоритм / класс для обработки подобных случаев, который можно легко реализовать в C #? И он должен поддерживать 100-500 клиентов одновременно (как минимум, это только положительно, если он может обрабатывать больше).

1 Ответ

2 голосов
/ 01 декабря 2011

Ваше решение было бы хорошо. Я думаю, что если вы используете выделенный поток и добавляете туда Thread.Sleep(1000), чтобы вы, как вы говорите, не жарили процессор. Избегайте блокировки вызовов в этом потоке например, убедитесь, что ваши вызовы SendPing и Drop являются асинхронными, поэтому этот поток делает только одно.

Другое решение заключается в использовании System.Timers.Timer для каждого клиентского соединения, интервал которого равен вашему таймеру пинга. Я использую этот метод и проверил это с 500 клиентами без проблем. (Интервал 20 сек). Если ваш интервал намного короче, я не рекомендовал бы это и смотрел бы другие решения, использующие один поток для проверки (например, ваше решение)

...