Асинхронная двусторонняя связь с Windows Named Pipes (.Net)

У меня есть служба Windows и графический интерфейс, которым нужно общаться друг с другом. Также можно отправлять сообщения в любое время.

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

Возможно ли сделать эту двустороннюю связь через один NamedPipe? Или мне нужно открыть две трубы (одну из GUI- > службы и одну из службы → GUI)?

Ответ 1

С помощью WCF вы можете использовать дуплексные именованные каналы

// Create a contract that can be used as a callback
public interface IMyCallbackService
{
    [OperationContract(IsOneWay = true)]
    void NotifyClient();
}

// Define your service contract and specify the callback contract
[ServiceContract(CallbackContract = typeof(IMyCallbackService))]
public interface ISimpleService
{
    [OperationContract]
    string ProcessData();
}

Внедрить службу

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class SimpleService : ISimpleService
{
    public string ProcessData()
    {
        // Get a handle to the call back channel
        var callback = OperationContext.Current.GetCallbackChannel<IMyCallbackService>();

        callback.NotifyClient();
        return DateTime.Now.ToString();
    }
}

Включить службу

class Server
{
    static void Main(string[] args)
    {
        // Create a service host with an named pipe endpoint
        using (var host = new ServiceHost(typeof(SimpleService), new Uri("net.pipe://localhost")))
        {
            host.AddServiceEndpoint(typeof(ISimpleService), new NetNamedPipeBinding(), "SimpleService");
            host.Open();

            Console.WriteLine("Simple Service Running...");
            Console.ReadLine();

            host.Close();
        }
    }
}

Создайте клиентское приложение, в этом примере класс Client выполняет контракт обратного вызова.

class Client : IMyCallbackService
{
    static void Main(string[] args)
    {
        new Client().Run();
    }

    public void Run()
    {
        // Consume the service
        var factory = new DuplexChannelFactory<ISimpleService>(new InstanceContext(this), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/SimpleService"));
        var proxy = factory.CreateChannel();

        Console.WriteLine(proxy.ProcessData());
    }

    public void NotifyClient()
    {
        Console.WriteLine("Notification from Server");
    }
}

Ответ 2

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

Итак, используйте 2 трубы с противоположными направлениями.

(Другой вариант - использование двух очередей MSMQ).

Ответ 3

Ваши именованные потоки потоков (сервер или клиент) должны быть сконструированы с помощью PipeDirection of InOut. Вам нужен один NamedPipeServerStream, возможно, в вашей службе, который может быть разделен произвольным количеством объектов NamedPipeClientStream. Постройте NamedPipeServerStream с именем канала и направлением, а NamedPipeClientStream - с именем канала, именем сервера и PipeDirection, и вам должно быть хорошо идти.