Communicating a Windows Service Project with a Windows Form Project

2

I just developed a Windows Service project (this will stay 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?

    
asked by anonymous 01.04.2015 / 20:18

2 answers

2

The name of this is inter-process communication ( IPC, Interprocess Communications ).

It can be done in several ways:

  • Sockets
  • Named Pipes
  • Memory-mapped files
  • among others

I'll show you how to do it using Named Pipes, based on this SOEN response , slightly modified 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 type of application, that is, it applies perfectly to you.

There are two main classes:

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

The example consists of exchanging numbers between the client and the server, each part incrementing the number with a random number from 0 to 10 and sending 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 send to customers, and customers will do the same.

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

    • Eachclienthasonlyonecolorfont
    • Theserverhasafontofeachcolor,correspondingtothecolorsoftheclients

NamedPipesServer.csproj

  • PipeServer.cs

    usingSystem;usingSystem.IO.Pipes;usingSystem.Threading;namespaceNamedPipesServer{publicclassPipeServer{privateThreadrunningThread;privatevolatileboolpareAssimQuePossivel;publicstringPipeName{get;privateset;}publicPipeServer(stringpipeName){this.PipeName=pipeName;}privatevoidServerLoop(){while(!this.pareAssimQuePossivel)this.ProcessNextClient();}publicvoidIniciar(){this.runningThread=newThread(this.ServerLoop);this.runningThread.Start();}publicvoidParar(){this.pareAssimQuePossivel=true;}publicvoidAbortar(){this.runningThread.Abort();}privatevoidProcessClientThread(objecto){using(varpipeStream=(NamedPipeServerStream)o){try{this.OnProcessClient(pipeStream);}finally{pipeStream.WaitForPipeDrain();if(pipeStream.IsConnected)pipeStream.Disconnect();}}}publiceventProcessClientProcessClient;protectedvirtualvoidOnProcessClient(NamedPipeServerStreamo){if(this.ProcessClient!=null)this.ProcessClient(this,o);}privatevoidProcessNextClient(){try{varpipeStream=newNamedPipeServerStream(this.PipeName,PipeDirection.InOut,-1);pipeStream.WaitForConnection();//Spawnanewthreadforeachrequestandcontinuewaitingvart=newThread(this.ProcessClientThread);t.Start(pipeStream);}catch(Exceptione){//Iftherearenomoreavailableconnections//(254isinusealready)thenjust//keeploopinguntiloneisavailable}}publicvoidEsperarAteDesconectar(){if(this.runningThread!=null)this.runningThread.Join();}}publicdelegatevoidProcessClient(PipeServersender,NamedPipeServerStreamstream);}
  • Program.cs

    usingSystem;usingSystem.IO;usingSystem.IO.Pipes;usingSystem.Threading;namespaceNamedPipesServer{staticclassProgram{staticvoidMain(string[]args){varserver=newPipeServer("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);
                }
            }
        }
    }
    
02.04.2015 / 01:17
1

My advice is: Use UDP socket
Whenever possible choose asynchronous methods for information exchange, so you ensure there are no locks or increase code complexity.

Here you have an example to send and receive packages UDP

    
02.04.2015 / 13:17