C# 两个进程/exe通讯方式 两个应用程序通讯方式

C# 两个exe通讯方式 两个应用程序通讯方式

1. 命名管道(Named Pipes)

1.1. 概述

命名管道是一种用于在同一台机器或网络中不同进程之间进行双向通信的机制。它支持同步和异步通信,适用于需要高效数据传输的场景。

1.2. 特点

双向通信:支持双向数据传输。
安全性:可以设置访问权限,确保通信的安全性。
跨网络:支持跨网络通信。

1.3. 实现方式

1.3.1. 服务器端(NamedPipeServerStream)
using System;
using System.IO.Pipes;
using System.Text;
using System.Threading.Tasks;

class PipeServer
{
    public static async Task StartServer()
    {
        using (var pipeServer = new NamedPipeServerStream("TestPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
        {
            Console.WriteLine("等待客户端连接...");
            await pipeServer.WaitForConnectionAsync();
            Console.WriteLine("客户端已连接。");

            // 接收数据
            byte[] buffer = new byte[256];
            int bytesRead = await pipeServer.ReadAsync(buffer, 0, buffer.Length);
            string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            Console.WriteLine($"收到消息:{receivedMessage}");

            // 发送回应
            string response = "Hello from server!";
            byte[] responseBytes = Encoding.UTF8.GetBytes(response);
            await pipeServer.WriteAsync(responseBytes, 0, responseBytes.Length);
            Console.WriteLine("已发送回应。");
        }
    }

    static void Main(string[] args)
    {
        Task.Run(() => StartServer()).Wait();
    }
}
1.3.2. 客户端(NamedPipeClientStream)
using System;
using System.IO.Pipes;
using System.Text;
using System.Threading.Tasks;

class PipeClient
{
    public static async Task StartClient()
    {
        using (var pipeClient = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut, PipeOptions.Asynchronous))
        {
            Console.WriteLine("尝试连接到服务器...");
            await pipeClient.ConnectAsync();
            Console.WriteLine("已连接到服务器。");

            // 发送数据
            string message = "Hello from client!";
            byte[] messageBytes = Encoding.UTF8.GetBytes(message);
            await pipeClient.WriteAsync(messageBytes, 0, messageBytes.Length);
            Console.WriteLine("已发送消息。");

            // 接收回应
            byte[] buffer = new byte[256];
            int bytesRead = await pipeClient.ReadAsync(buffer, 0, buffer.Length);
            string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            Console.WriteLine($"收到回应:{response}");
        }
    }

    static void Main(string[] args)
    {
        Task.Run(() => StartClient()).Wait();
    }
}

1.4. 使用场景

需要高效、双向通信的应用程序。
同一台机器或网络中的进程间通信。
需要传输大量数据或复杂数据结构。

2. 套接字(Sockets)

2.1. 概述

套接字是一种底层的通信机制,支持跨网络的进程间通信。它适用于需要跨不同机器或网络通信的应用程序。

2.2. 特点

灵活性高:支持多种协议(TCP、UDP)。
跨平台:可用于不同操作系统间的通信。
高性能:适用于实时数据传输和高并发应用。

2.3. 实现方式

2.3.1. 服务器端(TCP)
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

class SocketServer
{
    public static async Task StartServer()
    {
        TcpListener listener = new TcpListener(IPAddress.Any, 5000);
        listener.Start();
        Console.WriteLine("服务器已启动,等待连接...");

        using (TcpClient client = await listener.AcceptTcpClientAsync())
        {
            Console.WriteLine("客户端已连接。");
            NetworkStream stream = client.GetStream();

            // 接收数据
            byte[] buffer = new byte[1024];
            int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
            string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            Console.WriteLine($"收到消息:{receivedMessage}");

            // 发送回应
            string response = "Hello from server!";
            byte[] responseBytes = Encoding.UTF8.GetBytes(response);
            await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
            Console.WriteLine("已发送回应。");
        }

        listener.Stop();
    }

    static void Main(string[] args)
    {
        Task.Run(() => StartServer()).Wait();
    }
}
2.3.2. 客户端(TCP)
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

class SocketClient
{
    public static async Task StartClient()
    {
        using (TcpClient client = new TcpClient())
        {
            Console.WriteLine("尝试连接到服务器...");
            await client.ConnectAsync("127.0.0.1", 5000);
            Console.WriteLine("已连接到服务器。");

            NetworkStream stream = client.GetStream();

            // 发送数据
            string message = "Hello from client!";
            byte[] messageBytes = Encoding.UTF8.GetBytes(message);
            await stream.WriteAsync(messageBytes, 0, messageBytes.Length);
            Console.WriteLine("已发送消息。");

            // 接收回应
            byte[] buffer = new byte[1024];
            int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
            string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            Console.WriteLine($"收到回应:{response}");
        }
    }

    static void Main(string[] args)
    {
        Task.Run(() => StartClient()).Wait();
    }
}

2.4. 使用场景

需要跨不同机器或网络通信的应用程序。
实时通信,如聊天应用、游戏服务器等。
需要灵活控制通信协议和数据格式的场景。

3. 内存映射文件(Memory-Mapped Files)

3.1. 概述

内存映射文件允许多个进程共享同一块内存区域,实现高效的数据交换。它适用于需要频繁、快速共享大量数据的场景。

3.2. 特点

高性能:通过共享内存实现快速数据交换。
简单的数据共享:适用于需要在多个进程间共享复杂数据结构的应用程序。
跨语言支持:不同编程语言的进程可以通过内存映射文件进行通信。

3.3. 实现方式

3.3.1. 创建内存映射文件(服务器端)
using System;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Threading;

class MemoryMappedFileServer
{
    static void Main(string[] args)
    {
        using (var mmf = MemoryMappedFile.CreateOrOpen("SharedMemory", 1024))
        {
            Console.WriteLine("服务器已启动,等待消息...");

            using (var accessor = mmf.CreateViewAccessor())
            {
                while (true)
                {
                    byte[] buffer = new byte[256];
                    accessor.ReadArray(0, buffer, 0, buffer.Length);
                    string message = Encoding.UTF8.GetString(buffer).TrimEnd('\0');

                    if (!string.IsNullOrEmpty(message))
                    {
                        Console.WriteLine($"收到消息:{message}");

                        // 清空消息
                        accessor.WriteArray(0, new byte[256], 0, 256);

                        // 发送回应
                        string response = "Hello from server!";
                        byte[] responseBytes = Encoding.UTF8.GetBytes(response);
                        accessor.WriteArray(0, responseBytes, 0, responseBytes.Length);
                        Console.WriteLine("已发送回应。");
                    }

                    Thread.Sleep(1000); // 等待一段时间再检查
                }
            }
        }
    }
}
3.3.2. 读取内存映射文件(客户端)
using System;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Threading.Tasks;

class MemoryMappedFileClient
{
    static async Task Main(string[] args)
    {
        using (var mmf = MemoryMappedFile.OpenExisting("SharedMemory"))
        {
            using (var accessor = mmf.CreateViewAccessor())
            {
                // 发送消息
                string message = "Hello from client!";
                byte[] messageBytes = Encoding.UTF8.GetBytes(message);
                accessor.WriteArray(0, messageBytes, 0, messageBytes.Length);
                Console.WriteLine("已发送消息。");

                // 等待回应
                while (true)
                {
                    byte[] buffer = new byte[256];
                    accessor.ReadArray(0, buffer, 0, buffer.Length);
                    string response = Encoding.UTF8.GetString(buffer).TrimEnd('\0');

                    if (!string.IsNullOrEmpty(response))
                    {
                        Console.WriteLine($"收到回应:{response}");

                        // 清空回应
                        accessor.WriteArray(0, new byte[256], 0, 256);
                        break;
                    }

                    await Task.Delay(500);
                }
            }
        }
    }
}

3.4. 使用场景

需要在多个进程间高效共享大量数据。
实时数据交换,如视频流、实时监控数据等。
复杂数据结构的共享,如图像数据、结构化信息等。

4. 信号和消息(Windows Messages)

4.1. 概述

在 Windows 环境下,进程可以通过发送和接收窗口消息来进行通信。这种方法通常用于 GUI 应用程序之间的简单通信。

4.2. 特点

适用于 GUI 应用:主要用于具有窗口的应用程序之间的通信。
简单实现:适合于发送简单的消息或命令。

4.3. 实现方式

4.3.1. 发送消息(发送方)
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

class MessageSender
{
    // 引入 SendMessage 函数
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    // 自定义消息
    public const uint WM_USER = 0x0400;
    public const uint WM_CUSTOM = WM_USER + 1;

    static void Main(string[] args)
    {
        // 获取目标窗口句柄,可以通过窗口标题查找
        IntPtr hWnd = FindWindow(null, "接收消息的窗口标题");
        if (hWnd != IntPtr.Zero)
        {
            string message = "Hello from sender!";
            byte[] msgBytes = Encoding.UTF8.GetBytes(message);
            IntPtr lParam = Marshal.AllocHGlobal(msgBytes.Length + 1);
            Marshal.Copy(msgBytes, 0, lParam, msgBytes.Length);
            Marshal.WriteByte(lParam, msgBytes.Length, 0); // 添加 null 终止符

            SendMessage(hWnd, WM_CUSTOM, IntPtr.Zero, lParam);
            Marshal.FreeHGlobal(lParam);
            Console.WriteLine("已发送消息。");
        }
        else
        {
            Console.WriteLine("未找到目标窗口。");
        }
    }

    // 引入 FindWindow 函数
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
4.3.2. 接收消息(接收方)
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

class MessageReceiver : Form
{
    // 自定义消息
    public const uint WM_USER = 0x0400;
    public const uint WM_CUSTOM = WM_USER + 1;

    // 引入 WndProc
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_CUSTOM)
        {
            // 获取消息内容
            int length = 0;
            while (Marshal.ReadByte(m
上一篇:数据结构与算法:数据结构的前沿研究(最终章)


下一篇:【C语言】指针的定义与访问