Communicating a Windows Service project with a Windows Form project

Asked

Viewed 743 times

2

I just developed a Windows Service project (this will be running to check for system updates, via Clickonce). I need this Windows Service to communicate with a Form. I know that it is not possible to create a Form within a Service. What is the Safest Way to Make This Service Communicate with a Windows Form Project?

2 answers

2


The name of it is inter-process communication (IPC: Interprocess Communications).

Can be done in many ways:

  • Sockets
  • Named Pipes
  • Files mapped in memory
  • among others

I will show you how to do using Named Pipes, based on the this response from the SOEN, slightly altered to be functional (because the guy there did not test the answer, but I did).

The example consists of two console applications communicating, but could be any kind of application, ie, if it applies perfectly to your case.

Are two main classes:

  • PipeServer: allows serving multiple clients with the same named pipe
  • PipeClient: allows connecting to a named pipe server

The example consists in exchanging numbers between the client and the server, and each part increments the number with a random from 0 to 10 and sends it back to the other side.

You can start the server, and then start multiple clients. The server will print on the screen the numbers it receives and sends to the clients, and the clients will do the same.

  • Print from my screen with 1 server and 3 clients running:

    Tela com 1 servidor e 3 clientes

    • Each customer has only one color source
    • The server has a font of each color, corresponding to the client colors

Namedpipesserver.csproj

  • Pipeserver.Cs

    using System;
    using System.IO.Pipes;
    using System.Threading;
    
    namespace NamedPipesServer
    {
        public class PipeServer
        {
            private Thread runningThread;
            private volatile bool pareAssimQuePossivel;
    
            public string PipeName { get; private set; }
    
            public PipeServer(string pipeName)
            {
                this.PipeName = pipeName;
            }
    
            private void ServerLoop()
            {
                while (!this.pareAssimQuePossivel)
                    this.ProcessNextClient();
            }
    
            public void Iniciar()
            {
                this.runningThread = new Thread(this.ServerLoop);
                this.runningThread.Start();
            }
    
            public void Parar()
            {
                this.pareAssimQuePossivel = true;
            }
    
            public void Abortar()
            {
                this.runningThread.Abort();
            }
    
            private void ProcessClientThread(object o)
            {
                using (var pipeStream = (NamedPipeServerStream)o)
                {
                    try
                    {
                        this.OnProcessClient(pipeStream);
                    }
                    finally
                    {
                        pipeStream.WaitForPipeDrain();
                        if (pipeStream.IsConnected)
                            pipeStream.Disconnect();
                    }
                }
            }
    
            public event ProcessClient ProcessClient;
    
            protected virtual void OnProcessClient(NamedPipeServerStream o)
            {
                if (this.ProcessClient != null)
                    this.ProcessClient(this, o);
            }
    
            private void ProcessNextClient()
            {
                try
                {
                    var pipeStream = new NamedPipeServerStream(this.PipeName, PipeDirection.InOut, -1);
                    pipeStream.WaitForConnection();
    
                    // Spawn a new thread for each request and continue waiting
                    var t = new Thread(this.ProcessClientThread);
                    t.Start(pipeStream);
                }
                catch (Exception e)
                {
                    // If there are no more available connections
                    // (254 is in use already) then just
                    // keep looping until one is available
                }
            }
    
            public void EsperarAteDesconectar()
            {
                if (this.runningThread != null)
                    this.runningThread.Join();
            }
        }
    
        public delegate void ProcessClient(PipeServer sender, NamedPipeServerStream stream);
    }
    
  • Program.Cs

    using System;
    using System.IO;
    using System.IO.Pipes;
    using System.Threading;
    
    namespace NamedPipesServer
    {
        static class Program
        {
            static void Main(string[] args)
            {
                var server = new PipeServer("MeuNamedPipe");
                server.ProcessClient += ProcessClient;
                server.Iniciar();
                server.EsperarAteDesconectar();
            }
    
            private static volatile int number;
            private static ConsoleColor[] colors = new []
                                                   {
                                                       ConsoleColor.Blue,
                                                       ConsoleColor.Cyan, 
                                                       ConsoleColor.Green, 
                                                       ConsoleColor.Magenta, 
                                                       ConsoleColor.Red, 
                                                       ConsoleColor.White, 
                                                       ConsoleColor.Yellow, 
                                                   };
    
            private static object locker = new object();
    
            private static void ProcessClient(PipeServer sender, NamedPipeServerStream stream)
            {
                var reader = new StreamReader(stream);
                var writer = new StreamWriter(stream);
    
                var random = new Random();
    
                var color = colors[Interlocked.Increment(ref number)];
                writer.WriteLine(color);
    
                int num = 0;
                while (true)
                {
                    num += random.Next(10);
                    lock (locker)
                    {
                        Console.ForegroundColor = color;
                    Console.WriteLine("Send: " + num);
                    }
                    writer.WriteLine(num);
                    writer.Flush();
                    stream.WaitForPipeDrain();
    
                    Thread.Sleep(1000);
    
                    var recv = reader.ReadLine();
                    lock (locker)
                    {
                        Console.ForegroundColor = color;
                        Console.WriteLine("Received: " + recv);
                    }
                    var recvNum = int.Parse(recv);
                    num = recvNum;
    
                    Thread.Sleep(1000);
                }
            }
        }
    }
    

Namedpipeclient.csproj

  • Pipeclient.Cs

    using System;
    using System.IO.Pipes;
    using System.Threading;
    
    namespace NamedPipeClient
    {
        public class PipeClient
        {
            private Thread runningThread;
            private volatile bool pareAssimQuePossivel;
    
            public string PipeName { get; private set; }
    
            public bool PareAssimQuePossivel
            {
                get { return this.pareAssimQuePossivel; }
            }
    
            public PipeClient(string pipeName)
            {
                this.PipeName = pipeName;
            }
    
            private void ClientProcessorThread()
            {
                while (true)
                {
                    try
                    {
                        using (var pipeStream = new NamedPipeClientStream(".", this.PipeName, PipeDirection.InOut))
                        {
                            pipeStream.Connect(10000);
                            try
                            {
                                this.OnProcessServer(pipeStream);
                            }
                            finally
                            {
                                pipeStream.WaitForPipeDrain();
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        // If there are no more available connections
                        // (254 is in use already) then just
                        // keep looping until one is available
                    }
                }
            }
    
            public void Iniciar()
            {
                this.runningThread = new Thread(this.ClientProcessorThread);
                this.runningThread.Start();
            }
    
            public void Parar()
            {
                this.pareAssimQuePossivel = true;
            }
    
            public void Abortar()
            {
                this.runningThread.Abort();
            }
    
            public event ProcessServer ProcessServer;
    
            protected virtual void OnProcessServer(NamedPipeClientStream o)
            {
                if (this.ProcessServer != null)
                    this.ProcessServer(this, o);
            }
    
            public void EsperarAteDesconectar()
            {
                if (this.runningThread != null)
                    this.runningThread.Join();
            }
        }
    
        public delegate void ProcessServer(PipeClient sender, NamedPipeClientStream stream);
    }
    
  • Program.Cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.IO.Pipes;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace NamedPipeClient
    {
        static class Program
        {
            static void Main(string[] args)
            {
                var client = new PipeClient("MeuNamedPipe");
                client.ProcessServer += ProcessServer;
                client.Iniciar();
                client.EsperarAteDesconectar();
            }
    
            private static void ProcessServer(PipeClient sender, NamedPipeClientStream stream)
            {
                var reader = new StreamReader(stream);
                var writer = new StreamWriter(stream);
    
                var random = new Random();
    
                var colorStr = reader.ReadLine();
                var color = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), colorStr);
                Console.ForegroundColor = color;
    
                int num;
                while (true)
                {
                    var recv = reader.ReadLine();
                    Console.WriteLine("Received: " + recv);
                    var recvNum = int.Parse(recv);
                    num = recvNum;
    
                    Thread.Sleep(1000);
    
                    num += random.Next(10);
                    Console.WriteLine("Send: " + num);
                    writer.WriteLine(num);
                    writer.Flush();
                    stream.WaitForPipeDrain();
    
                    Thread.Sleep(1000);
                }
            }
        }
    }
    
  • I was told to do it by Startup. I didn’t mean it very well. Vicê has heard?

1

My advice is: Use UDP socket
Whenever it is possible to choose asynchronous methods for information exchange, so you ensure that there will be no lockouts or increase code complexity.

Here you have an example for sending and receiving packages UDP

  • I was told to do it by Startup. I didn’t mean it very well. Vicê has heard?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.