Подключение по именованному каналу из службы Windows (сеанс № 0) к настольному приложению (сеанс № 1) - PullRequest
7 голосов
/ 29 ноября 2010

Дано :
- приложение - настольный графический интерфейс (WPF) .NET app
- служба Windows, наблюдающая за приложением (также .NET)

Служба Windows периодическиПриложение "pings", чтобы убедиться, что оно исправно (и если это не так, winservice перезапустит его).
Я собирался реализовать "ping" через именованные каналы.Чтобы сделать вещи проще, я решил сделать это с WCF.Приложение содержит WCF-сервис (одна операция Ping возвращает что-то).Служба Windows является клиентом для этой службы WCF, периодически ее запускающей на основе таймера.

Это все в Windows 7.
Служба Windows работает под LocalService (в сеансе # 0).
Настольное приложение работает под текущим вошедшим пользователем (в сеансе # 1).

Проблема :
Служба Windows не может увидеть конечную точку WCF (с NetNamedPipeBinding), созданную и прослушиваемую в настольном приложении.Это означает, что при вызове через прокси wcf я получаю следующее исключение: «Конечная точка канала 'net.pipe: // localhost / HeartBeat' не может быть найдена на вашем локальном компьютере»

Я уверен, что код в порядкепотому что другое настольное приложение (в сеансе # 1) может видеть конечную точку.

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

Ответы [ 2 ]

6 голосов
/ 29 ноября 2010

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

Видимость службы работает наоборот, поскольку служба Windows может работать с SeCreateGlobalPrivilege, иОбъект разделяемой памяти, через который сервис публикует имя канала, может быть создан в глобальном пространстве имен ядра, видимом для других сеансов.Интерактивные приложения не могут легко получить эту привилегию в Windows7, поэтому службы WCF в таких приложениях прибегают к публикации канала в пространстве имен локального ядра, видимого только в пределах их собственного сеанса.

4 голосов
/ 29 ноября 2010

Наконец-то я нашел решение - использовать именованные каналы из System.IO.Pipes напрямую.Кажется, что реализация поддержки каналов WCF не использует System.IO.Pipes.

Сервер :

using (var pipeServer = new NamedPipeServerStream("mypipe", PipeDirection.Out, 1))
{
    try
    {
        while (true)
        {
            // #1 Connect:
            try
            {
                pipeServer.WaitForConnection();
            }
            catch (ObjectDisposedException)
            {
                yield break;
            }
            if (ae.IsCanceled())
                return;

            // #2: Sending response:
            var response = Encoding.ASCII.GetBytes(DateTime.Now.ToString());
            try
            {
                pipeServer.Write(response, 0, response.Length);
            }
            catch (ObjectDisposedException)
            {
                return;
            }

            // #3: Disconnect:
            pipeServer.Disconnect();
        }
    }
    finally
    {
        if (pipeServer.IsConnected)
            pipeServer.Disconnect();
    }
}

Клиент :

using (var pipeClient = new NamedPipeClientStream(".", "mypipe", PipeDirection.In))
{
    try
    {
        try
        {
            pipeClient.Connect(TIMEOUT);
        }
        catch(TimeoutException ex)
        {
            // nobody answers to us
            continue;
        }
        using (var sr = new StreamReader(pipeClient))
        {
            string temp;
            while ((temp = sr.ReadLine()) != null)
            {
                // got response
            }
        }
    }
    catch(Exception ex)
    {
        // pipe error
        throw;
    }
}
...