目录

C-进程间通信

C# 进程间通信

在 C# 中,进程间通信(Inter-Process Communication,简称 IPC)是指不同的进程之间进行数据传输和信息交换的技术。进程间通信有多种实现方式,不同的方式适用于不同的应用场景。下面我们将详细介绍 C# 中几种常见的进程间通信方式,包括每种方式的应用场景、实现方法以及优缺点。

1. 命名管道 (Named Pipes)

概述

命名管道是一种半双工或全双工的进程间通信方式,可以用于本地或远程的进程通信。它类似于匿名管道(用于单向通信),但命名管道有一个名称,允许两个不相关的进程进行双向通信。

优点

支持双向通信。

支持跨网络的通信。

高效,适合大量数据传输。

缺点

复杂度相对较高。

仅适合相对短连接时间的通信。

示例

  • 服务器端(监听端):
using System.IO.Pipes;
using System.Text;

class PipeServer
{
    public static void Main()
    {
        using (var pipeServer = new NamedPipeServerStream("TestPipe", PipeDirection.InOut))
        {
            pipeServer.WaitForConnection();
            Console.WriteLine("Client connected.");

            byte[] buffer = new byte[1024];
            int bytesRead = pipeServer.Read(buffer, 0, buffer.Length);
            string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            Console.WriteLine($"Received: {message}");

            string response = "Hello from server";
            byte[] responseBytes = Encoding.UTF8.GetBytes(response);
            pipeServer.Write(responseBytes, 0, responseBytes.Length);
        }
    }
}
  • 客户端(连接端):
using System.IO.Pipes;
using System.Text;

class PipeClient
{
    public static void Main()
    {
        using (var pipeClient = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut))
        {
            pipeClient.Connect();
            Console.WriteLine("Connected to server.");

            string message = "Hello from client";
            byte[] messageBytes = Encoding.UTF8.GetBytes(message);
            pipeClient.Write(messageBytes, 0, messageBytes.Length);

            byte[] buffer = new byte[1024];
            int bytesRead = pipeClient.Read(buffer, 0, buffer.Length);
            string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            Console.WriteLine($"Received: {response}");
        }
    }
}

2. 共享内存 (Memory-Mapped Files)

概述

共享内存允许多个进程将数据写入和读取同一个内存区域。通过内存映射文件,进程可以将文件的内容映射到内存中,并通过该映射的内存进行通信。

优点

非常高效,适用于大量数据传输。

无需中间数据传输的开销。

缺点

需要对内存管理有较高要求。

同步问题需要额外处理,防止多个进程同时修改数据。

示例

  • 进程 A 和 进程 B 共享内存:
using System;
using System.IO.MemoryMappedFiles;
using System.Text;

class MemoryMappedFileExample
{
    public static void Main()
    {
        // 创建或打开内存映射文件
        using (var mmf = MemoryMappedFile.CreateOrOpen("SharedMemory", 1024))
        {
            // 写入数据
            using (var writer = mmf.CreateViewAccessor(0, 1024))
            {
                string message = "Hello from process A";
                byte[] buffer = Encoding.UTF8.GetBytes(message);
                writer.WriteArray(0, buffer, 0, buffer.Length);
                Console.WriteLine("Written to shared memory.");
            }

            // 读取数据
            using (var reader = mmf.CreateViewAccessor(0, 1024))
            {
                byte[] buffer = new byte[1024];
                reader.ReadArray(0, buffer, 0, buffer.Length);
                string receivedMessage = Encoding.UTF8.GetString(buffer).TrimEnd('\0');
                Console.WriteLine($"Read from shared memory: {receivedMessage}");
            }
        }
    }
}

3. 信号量和互斥量 (Semaphore & Mutex)

概述

信号量和互斥量用于进程间的同步,而不是数据传输。它们可以确保一个进程在访问资源时,另一个进程不能同时访问相同的资源。

优点

简单高效,用于同步的控制机制。

适用于资源访问控制场景。

缺点

不能传输数据。

仅用于同步进程或线程的执行顺序。

示例

  • 互斥量:
using System;
using System.Threading;

class MutexExample
{
    static void Main()
    {
        using (Mutex mutex = new Mutex(false, "Global\\MyMutex"))
        {
            if (mutex.WaitOne(TimeSpan.FromSeconds(10), false))
            {
                try
                {
                    Console.WriteLine("Mutex acquired, processing...");
                    // 模拟处理
                    Thread.Sleep(5000);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
            else
            {
                Console.WriteLine("Unable to acquire the mutex, exiting...");
            }
        }
    }
}

4. Socket 通信

概述

套接字(Socket)是一种常见的网络通信方式,不仅适用于进程间通信,还可以用于不同机器之间的通信。它可以使用 TCP 或 UDP 协议进行数据传输。

优点

适用于本地和远程通信。

支持复杂的双向通信和实时性要求。

缺点

需要处理网络协议的细节,较为复杂。

可能引入网络延迟和不稳定性。

示例

  • TCP 服务器:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

class TcpServer
{
    public static void Main()
    {
        TcpListener server = new TcpListener(IPAddress.Any, 5000);
        server.Start();
        Console.WriteLine("Server started...");

        while (true)
        {
            TcpClient client = server.AcceptTcpClient();
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte[1024];
            int bytesRead = stream.Read(buffer, 0, buffer.Length);
            string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            Console.WriteLine($"Received: {message}");

            byte[] response = Encoding.UTF8.GetBytes("Hello from server");
            stream.Write(response, 0, response.Length);
            client.Close();
        }
    }
}
  • TCP 客户端:
using System;
using System.Net.Sockets;
using System.Text;

class TcpClientExample
{
    public static void Main()
    {
        TcpClient client = new TcpClient("127.0.0.1", 5000);
        NetworkStream stream = client.GetStream();

        string message = "Hello from client";
        byte[] data = Encoding.UTF8.GetBytes(message);
        stream.Write(data, 0, data.Length);

        byte[] buffer = new byte[1024];
        int bytesRead = stream.Read(buffer, 0, buffer.Length);
        string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
        Console.WriteLine($"Received: {response}");

        client.Close();
    }
}

5. 消息队列 (Message Queue)

概述

消息队列是一种异步通信机制,允许进程将消息发送到队列,接收方可以从队列中读取消息进行处理。它允许不同进程在不同时间段内发送和接收消息。

优点

异步,适合非实时通信。

消息可以在系统宕机或重启后继续存在。

缺点

延迟较高,适合非实时应用。

配置相对复杂,依赖外部的消息队列服务。

示例

C# 支持使用 MSMQ(Microsoft Message Queue)进行消息队列通信。不过,目前消息队列的主流使用场景多由第三方中间件(如 RabbitMQ、Kafka)承载。

6. WCF (Windows Communication Foundation)

概述

WCF 是一种强大的通信框架,支持进程间、跨平台、跨网络的通信。它提供了多种绑定(如 HTTP、TCP、命名管道等),并且支持面向服务(SOA)的架构。

优点

灵活,支持多种传输协议。

可配置,适合大规模分布式应用。

缺点

配置复杂度较高。

对于简单的进程间通信来说,可能有些过重。

示例

WCF 适合大型应用,在简单进程间通信场景下较少使用。可以通过命名管道或 TCP 绑定来实现。