当前位置:网站首页>. Net interprocess communication

. Net interprocess communication

2022-07-06 04:13:00 chaney1992

One 、 Preface :

  In project development, we often encounter , The need for communication calls between multiple processes .

  The common ways are :

  • The Conduit : Including named pipes and anonymous pipes
  • Memory mapped files : With the help of the mapping relationship between files and memory space , application ( Including multiple processes ) It can directly perform read and write operations on memory , So as to realize inter process communication
  • Socket: Use sockets to communicate between different processes , In this way , You need to occupy at least one port of the system
  • SendMessage: Communicate through the window handle , This communication method is based on  Windows  news  WM_COPYDATA  To achieve
  • Message queue : In the case of low performance requirements , We can use  Msmq. But in the real world , Usually use  ActiveMQKafkaRocketMQRabbitMQ Wait for these message oriented middleware optimized for specific scenarios , For maximum performance or scalability benefits

  among , The Conduit 、 Memory mapped files 、SendMessage The way , It is usually used for communication between processes on a single machine , Use these three methods on a single machine , Than using  Socket  Be relatively efficient , And it is easier to control the network .

  This article will introduce the use of .Net Pipeline mode realizes multi process communication .

Two 、 The Conduit

  Pipelines provide a platform for interprocess communication . There are two types of pipes :

  • Anonymous pipeline :

   Anonymous pipes provide interprocess communication on the local computer . Compared with pipe naming , Although anonymous pipes require less overhead , But the services provided are limited .

   Anonymous pipes are one-way , Cannot be used through the network . Only one server instance is supported .

   Anonymous pipes can be used for inter thread communication , It can also be used for communication between parent and child processes , Because the pipeline handle can be easily passed to the child process created .

  • name pipes :

   Named pipes provide interprocess communication between a pipeline server and one or more pipeline clients .

   Named pipes can be unidirectional , It can also be two-way . They support message based communication , It also allows multiple clients to connect to the server process at the same time with the same pipe name .

   Named pipes also support simulation , In this way, the connection process can use its own permissions on the remote server .

3、 ... and 、 application

 1、 Anonymous pipeline : Realization effect : The server passes the input content to the client for output .

  • Server side : Create an output anonymous pipeline , Pipe console input to child processes
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;

namespace IpcServer
{
    class AonymousPipeServer
    {
        public static void Run()
        {
            // Client process 
            Process pipeClient = new Process();
            pipeClient.StartInfo.FileName = "IpcClient.exe";
            // Create an output anonymous pipeline 、 Specifies that the handle is inherited by the child process 
            using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable))
            {
                Console.WriteLine("[SERVER]  Pipeline transmission mode : {0}.", pipeServer.TransmissionMode);
                // Pass the handle of the client process to the server .
                pipeClient.StartInfo.Arguments = pipeServer.GetClientHandleAsString();
                pipeClient.StartInfo.UseShellExecute = false;
                pipeClient.Start();
                pipeServer.DisposeLocalCopyOfClientHandle();
                try
                {
                    //  Read the input content of the server , Send to client process 
                    using (StreamWriter sw = new StreamWriter(pipeServer))
                    {
                        sw.AutoFlush = true;
                        //  send out “ Sync message ” And wait for the client to receive .
                        sw.WriteLine("SYNC");
                        // Wait for the client to read all content 
                        pipeServer.WaitForPipeDrain();
                        //  Send console data to child process 
                        Console.Write("[SERVER]  Input text : ");
                        sw.WriteLine(Console.ReadLine());
                    }
                }
                catch (IOException e)
                {
                    Console.WriteLine("[SERVER]  abnormal : {0}", e.Message);
                }
            }
            pipeClient.WaitForExit();
            pipeClient.Close();
            Console.WriteLine("[SERVER]  Client exit , The server terminates .");
        }
    }
}
  • client : Create an input pipe , Get the incoming data from the server from the pipeline and output
using System;
using System.IO;
using System.IO.Pipes;

namespace IpcClient
{
    class AonymousPipeClient
    {
        public static void Run(string[] args)
        {
            if (args.Length > 0)
            {
                // Create an input type anonymous pipeline 
                using (PipeStream pipeClient = new AnonymousPipeClientStream(PipeDirection.In, args[0]))
                {
                    Console.WriteLine("[CLIENT]  Current pipeline transmission mode : {0}.", pipeClient.TransmissionMode);
                    // Create read stream , Read... From the pipe 
                    using (StreamReader sr = new StreamReader(pipeClient))
                    {
                        string temp;
                        //  Waiting for the message from the server 
                        do
                        {
                            Console.WriteLine("[CLIENT]  Synchronization waiting ...");
                            temp = sr.ReadLine();
                        }
                        while (!temp.StartsWith("SYNC"));
                        // Read the server data and echo to the console.
                        while ((temp = sr.ReadLine()) != null)
                        {
                            Console.WriteLine("[CLIENT]  Respond to : " + temp);
                        }
                    }
                }
            }
            Console.Write("[CLIENT]  Any key to exit ...");
            Console.ReadLine();
        }
    }
}

  Effect of the sample :

 

 2、 name pipes :

  • Server side : Read the file address sent by the client through the pipeline , Read it in the server and return it to the client
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;

namespace IpcServer
{
    public class NamedPipeServer
    {
        private static int numThreads = 4;
        public static void Run()
        {
            int i;
            Thread[] servers = new Thread[numThreads];

            Console.WriteLine("\n***  Named pipe server example  ***\n");
            Console.WriteLine(" Wait for the client to connect ...\n");
            for (i = 0; i < numThreads; i++)
            {
                servers[i] = new Thread(ServerThread);
                servers[i].Start();
            }
            Thread.Sleep(250);
            while (i > 0)
            {
                for (int j = 0; j < numThreads; j++)
                {
                    if (servers[j] != null)
                    {
                        if (servers[j].Join(250))
                        {
                            Console.WriteLine("Server thread[{0}]  end .", servers[j].ManagedThreadId);
                            servers[j] = null;
                            i--;    //  Reduce the number of threads 
                        }
                    }
                }
            }
            Console.WriteLine("\n The server thread has completed , Exiting .");
            Console.ReadLine();
        }

        private static void ServerThread(object data)
        {
            // Pipe name 、 Pipeline direction 
            NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, numThreads);
            int threadId = Thread.CurrentThread.ManagedThreadId;
            //  Wait for the client to connect 
            pipeServer.WaitForConnection();
            Console.WriteLine(" Client connection successful  thread[{0}].", threadId);
            try
            {
                // Read the customer's request . After the client writes to the pipeline , Its security token will be available 
                StreamString ss = new StreamString(pipeServer);
                // Use the string expected by the client to verify our identity to the connected client .
                ss.WriteString("I am the one true server!");
                string filename = ss.ReadString();
                // Read the contents of the file when simulating the client .
                ReadFileToStream fileReader = new ReadFileToStream(ss, filename);
                Console.WriteLine(" Read the file : {0}  Threads [{1}]  Pipeline user : {2}.", filename, threadId, pipeServer.GetImpersonationUserName());
                pipeServer.RunAsClient(fileReader.Start);
            }
            catch (IOException e)
            {
                Console.WriteLine(" abnormal : {0}", e.Message);
            }
            pipeServer.Close();
        }
    }

    // Define the data protocol used to read and write strings on the stream 
    public class StreamString
    {
        private Stream ioStream;
        private UnicodeEncoding streamEncoding;
        public StreamString(Stream ioStream)
        {
            this.ioStream = ioStream;
            streamEncoding = new UnicodeEncoding();
        }

        public string ReadString()
        {
            int len = 0;
            len = ioStream.ReadByte() * 256;
            len += ioStream.ReadByte();
            byte[] inBuffer = new byte[len];
            ioStream.Read(inBuffer, 0, len);
            return streamEncoding.GetString(inBuffer);
        }

        public int WriteString(string outString)
        {
            byte[] outBuffer = streamEncoding.GetBytes(outString);
            int len = outBuffer.Length;
            if (len > UInt16.MaxValue)
            {
                len = (int)UInt16.MaxValue;
            }
            ioStream.WriteByte((byte)(len / 256));
            ioStream.WriteByte((byte)(len & 255));
            ioStream.Write(outBuffer, 0, len);
            ioStream.Flush();
            return outBuffer.Length + 2;
        }
    }

    //  Contains methods executed in the context of impersonating users 
    public class ReadFileToStream
    {
        private string fn;
        private StreamString ss;
        public ReadFileToStream(StreamString str, string filename)
        {
            fn = filename;
            ss = str;
        }

        public void Start()
        {
            string contents = File.ReadAllText(fn);
            ss.WriteString(contents);
        }
    }
}
  • client : After connecting the server named pipe , Send the file path to read ; Read the contents of the file returned by the server and output
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;
using System.Text;
using System.Threading;

namespace IpcClient
{
    class NamedPipeClient
    {
        private static int numClients = 4;

        public static void Run(string[] args)
        {
            if (args.Length > 0)
            {
                if (args[0] == "spawnclient")
                {
                    //. Representing this machine ( It can be replaced by specific IP)
                    var pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation);
                    Console.WriteLine(" Connect server ...\n");
                    pipeClient.Connect();
                    var ss = new StreamString(pipeClient);
                    // Validate the server's signature string.
                    if (ss.ReadString() == "I am the one true server!")
                    {
                        // Send file path , The server returns after reading 
                        ss.WriteString(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "namedpipeTxt.txt"));

                        // Output file content 
                        Console.Write($" The contents of the document :{ss.ReadString()}\r\n");
                    }
                    else
                    {
                        Console.WriteLine(" The server failed to verify ");
                    }
                    pipeClient.Close();
                    Console.ReadLine();
                }
            }
            else
            {
                Console.WriteLine("\n***  Named pipe client example  ***\n");
                StartClients();
            }
        }

        //  Start client 
        private static void StartClients()
        {
            string currentProcessName = Environment.CommandLine;
            currentProcessName = currentProcessName.Trim('"', ' ');
            currentProcessName = Path.ChangeExtension(currentProcessName, ".exe");
            Process[] plist = new Process[numClients];
            Console.WriteLine(" Generate client process ...\n");
            if (currentProcessName.Contains(Environment.CurrentDirectory))
            {
                currentProcessName = currentProcessName.Replace(Environment.CurrentDirectory, String.Empty);
            }
            // Compatible processing 
            currentProcessName = currentProcessName.Replace("\\", String.Empty);
            currentProcessName = currentProcessName.Replace("\"", String.Empty);
            int i;
            for (i = 0; i < numClients; i++)
            {
                // Start the client process , Use the same named pipe 
                plist[i] = Process.Start(currentProcessName, "spawnclient");
            }
            while (i > 0)
            {
                for (int j = 0; j < numClients; j++)
                {
                    if (plist[j] != null)
                    {
                        if (plist[j].HasExited)
                        {
                            Console.WriteLine($" Client process [{plist[j].Id}] Has been withdrawn from .");
                            plist[j] = null;
                            i--;
                        }
                        else
                        {
                            Thread.Sleep(250);
                        }
                    }
                }
            }
            Console.WriteLine("\n Client process completed , Exiting ");
        }
    }

    // Define the data protocol used to read and write strings on the stream 
    public class StreamString
    {
        private Stream ioStream;
        private UnicodeEncoding streamEncoding;

        public StreamString(Stream ioStream)
        {
            this.ioStream = ioStream;
            streamEncoding = new UnicodeEncoding();
        }

        public string ReadString()
        {
            int len;
            len = ioStream.ReadByte();
            len = len * 256;
            len += ioStream.ReadByte();
            var inBuffer = new byte[len];
            ioStream.Read(inBuffer, 0, len);

            return streamEncoding.GetString(inBuffer);
        }

        public int WriteString(string outString)
        {
            byte[] outBuffer = streamEncoding.GetBytes(outString);
            int len = outBuffer.Length;
            if (len > UInt16.MaxValue)
            {
                len = (int)UInt16.MaxValue;
            }
            ioStream.WriteByte((byte)(len / 256));
            ioStream.WriteByte((byte)(len & 255));
            ioStream.Write(outBuffer, 0, len);
            ioStream.Flush();

            return outBuffer.Length + 2;
        }
    }
}

Four 、 summary :

  If you use pipes to realize the communication between processes , You can choose as follows :

  • If you only need one-way communication , And the relationship between the two processes is a parent-child process , Anonymous pipes can be used
  • If you need two-way communication , Then use named pipes
  • If we can't decide what to choose , Then choose the two-way communication mode of named pipeline . On today's computers , We can ignore the difference between the performance of named pipes and anonymous pipes . And the named pipeline of two-way communication , One way , It can also be bidirectional , More flexible

Source code :IpcService

原网站

版权声明
本文为[chaney1992]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202132237063255.html