WCF - обратный вызов клиента и опрос для «ведения списка подписчиков» - PullRequest
7 голосов
/ 08 декабря 2009

Я хочу создать простой пример клиент-сервер в WCF. Я провел некоторое тестирование с обратными вызовами, и пока он работает нормально. Я немного поиграл со следующим интерфейсом:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IStringCallback))]
public interface ISubscribeableService
{
    [OperationContract]
    void ExecuteStringCallBack(string value);

    [OperationContract]
    ServerInformation Subscribe(ClientInformation c);

    [OperationContract]
    ServerInformation Unsubscribe(ClientInformation c);
}

Это простой пример. немного скорректированы. Вы можете попросить сервер «выполнить строковый обратный вызов», и в этом случае сервер отменил строку и вызовет все подписанные обратные вызовы клиента.

Теперь возникает вопрос: если я хочу внедрить систему, в которой все клиенты «регистрируются» на сервере, и сервер может «спрашивать» клиентов, живы ли они, вы бы реализовали это с помощью обратных вызовов (так вместо этого "обратного вызова строки" - своего рода TellTheClientThatIAmStillHereCallback). Проверяя состояние связи по обратному вызову, я также могу «узнать», мертв ли ​​клиент. Нечто похожее на это:

Subscribers.ForEach(delegate(IStringCallback callback)
                    {
                        if (((ICommunicationObject)callback).State == CommunicationState.Opened)
                        {
                            callback.StringCallbackFunction(new string(retVal));
                        }
                        else
                        {
                            Subscribers.Remove(callback);
                        }
                    });

Моя проблема, поставь по-другому:

  • На сервере может быть 3 клиента
  • Клиент A умирает (я вытащил вилку ноутбука)
  • Сервер умирает и возвращается онлайн
  • Подходит новый клиент

Таким образом, в основном, вы бы использовали обратные вызовы для проверки "все еще живого состояния" клиентов, или вы бы использовали опрос и отслеживали "как долго я не слышал о клиенте" ...

Ответы [ 4 ]

3 голосов
/ 15 декабря 2009

Вы можете обнаружить большинство изменений состояния соединения с помощью событий Closed, Closing и Faulted из ICommunicationObject. Вы можете подключить их одновременно с настройкой обратного вызова. Это определенно лучше, чем опрос.

IIRC, событие Faulted сработает только после того, как вы фактически попытаетесь использовать обратный вызов (безуспешно). Таким образом, если клиент просто исчезнет - например, после полной перезагрузки или выключения питания, - вы сразу не будете уведомлены. Но нужно ли вам быть? И если да, то почему?

Обратный вызов WCF может произойти сбой в любое время, и вы всегда должны помнить об этом. Даже если с клиентом и сервером все в порядке, вы все равно можете получить отказавший канал из-за исключения или сбоя сети. Или, может быть, клиент когда-то отключился от вашего последнего опроса до текущей операции. Дело в том, что пока вы кодируете свои операции обратного вызова в обороне (что в любом случае является хорошей практикой), то перехват событий выше, как правило, достаточно для большинства проектов. Если по какой-либо причине возникает ошибка - в том числе клиент не отвечает - событие Faulted запускается и запускает ваш код очистки.

Это то, что я бы назвал пассивным / ленивым подходом и требует меньшего количества кодирования и болтовни в сети, чем подходы опроса или поддержания активности.

2 голосов
/ 07 марта 2010

Если вы включаете надежные сеансы, WCF внутренне поддерживает механизм контроля активности. Через скрытые тестовые сообщения инфраструктуры он регулярно проверяет, есть ли другой конец. Временной интервал этих проверок может зависеть от свойства ReliableSession.InactivityTimeout. Если вы установите для свойства, скажем, 20 секунд, то событие ICommunicationObject.Fapted будет вызвано примерно через 20–30 (максимум) секунд после того, как на другой стороне произошел сбой службы.

Если вы хотите быть уверены, что клиентские приложения всегда остаются «автоматически подключенными», даже после временных сбоев службы, вы можете использовать рабочий поток (из пула потоков), который неоднократно пытается создать новый экземпляр прокси на клиентская сторона, и вызывает инициирующую сеанс операцию после того, как там возникло событие Faults.

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

Используя первый или второй подход, вы можете реализовать архитектуру служебной шины (шаблон-посредник), гарантирующую, что все экземпляры клиентских приложений постоянно готовы к получению «спонтанных» служебных сообщений при каждом запуске службы.

Конечно, это работает только в том случае, если надежный сеанс «как таковой» настроен правильно для начала (с использованием привязки к сеансу и применения ServiceContractAttribute.SessionMode, ServiceBehaviorAttribute.InstanceContextMode, OperationContractAttribute.IsInitiating и OperationContractAttribute.atings свойства в значимых отношениях).

0 голосов
/ 13 декабря 2009

Я не пытался использовать обратные вызовы WCF по проводам, но я использовал их для межпроцессного взаимодействия. У меня возникла проблема, когда вызовы, которые отправлялись, заканчивались в том же потоке и делали блокировку службы, когда были вызовы, которые зависели от одного и того же потока.

Это может относиться к проблеме, которая у вас есть в настоящее время, поэтому вот что я должен был сделать, чтобы решить проблему.

Поместите этот атрибут на сервер и клиент класса реализации сервера WCF

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class WCFServerClass

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

Я также использовал пул потоков на стороне клиента, чтобы убедиться, что на стороне клиента нет проблем с потоками

0 голосов
/ 08 декабря 2009

У меня была похожая ситуация с использованием WCF и обратных вызовов. Я не хотел использовать опрос, но я использовал протокол «reilable», поэтому, если клиент умер, он зависал на сервере до истечения времени ожидания и сбоя.

Я не знаю, является ли это наиболее правильным или элегантным решением, но я создал класс в сервисе для представления клиентского прокси. Каждый экземпляр этого класса содержал ссылку на клиентский прокси и выполнял бы функцию обратного вызова всякий раз, когда сервер устанавливал свойство «сообщения» класса. Делая это, когда клиент отключается, отдельный класс-оболочка получает исключение тайм-аута и удаляет себя из списка слушателей сервера, но службе не придется его ждать. Это на самом деле не отвечает на ваш вопрос об определении, жив ли клиент, но это еще один способ структурировать сервис для решения проблемы. Если вам нужно было узнать, когда клиент умер, вы сможете узнать, когда клиентская оболочка удалилась из списка слушателей.

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