前言
在 C# 开发中,多线程通信对大多数开发者而言已是驾轻就熟——无论是 AsyncLocal、ThreadLocal,还是通过 CallContext 的 GetData/SetData 方法,都能信手拈来。然而,多进程通信(Inter-Process Communication, IPC)虽然应用场景广泛,但掌握程度普遍不如多线程通信深入。
本文将系统梳理 C# 中常见的多进程通信方式,不包含消息中间件(如 RabbitMQ、Kafka)、数据库、gRPC、WebSocket、SignalR 等高级通信手段,仅聚焦于 .NET Framework / .NET 中原生或基于 Windows 系统支持的 IPC 机制,并以 C# 代码示例说明。
★
⚠️ 注:本文示例基于 .NET Framework 编写,部分技术(如 .NET Remoting)在 .NET Core/.NET 5+ 中已被弃用,仅适用于传统 Windows 桌面应用。
1. 共享内存(Memory-Mapped Files)
共享内存是高性能进程间通信的常用方式。C# 提供了 MemoryMappedFile 类,封装了底层 Win32 API,使用简便。
服务端(写入数据)
// 使用 Accessor 方式写入
usingvar mmfAccessor = MemoryMappedFile.CreateNew("ProcessCommunicationAccessor", 500);
usingvar accessor = mmfAccessor.CreateViewAccessor();
byte[] helloBytes = Encoding.UTF8.GetBytes("Accessor");
accessor.WriteArray(0, helloBytes, 0, helloBytes.Length);
richTextBox1.Text += Environment.NewLine + "Accessor Send Val:
Accessor";
// 使用 Stream 方式写入
usingvar mmfStream = MemoryMappedFile.CreateNew("ProcessCommunicationStream", 500);
usingvar stream = mmfStream.CreateViewStream();
byte[] streamBytes = Encoding.UTF8.GetBytes("Stream");
stream.Write(streamBytes, 0, streamBytes.Length);
richTextBox1.Text += Environment.NewLine + "Stream Send Val:
Stream";
客户端(读取数据)
// 读取 Accessor 数据
usingvar mmfAccessor = MemoryMappedFile.OpenExisting("ProcessCommunicationAccessor");
usingvar accessor = mmfAccessor.CreateViewAccessor();
byte[] buffer = newbyte[500];
accessor.ReadArray(0, buffer, 0, buffer.Length);
string str = Encoding.UTF8.GetString(buffer).Trim('\0');
richTextBox1.Text += Environment.NewLine + "Accessor Read Val: " +
str;
// 读取 Stream 数据
usingvar mmfStream = MemoryMappedFile.OpenExisting("ProcessCommunicationStream");
usingvar stream = mmfStream.CreateViewStream();
usingvar reader = new StreamReader(stream);
string streamStr = reader.ReadToEnd().Trim('\0');
richTextBox1.Text += Environment.NewLine + "Stream Read Val: " +
streamStr;
★
💡 提示:建议使用 CreateOrOpen 避免因文件不存在导致异常。注意字符串末尾可能包含空字符(\0),需手动去除。
2. Windows 消息队列(MSMQ)
MSMQ 是 Windows 内置的消息队列服务,需手动启用(控制面板 → 程序和功能 → 启用或关闭 Windows 功能 → Microsoft Message Queue)。
服务端(发送消息)
using var queue = new MessageQueue(@".\Private$\MessageQueue");
queue.Send("Message HelloWorld");
richTextBox1.Text += Environment.NewLine + "MessageQueue Send Val:
Message HelloWorld";
客户端(异步接收)
var context =
WindowsFormsSynchronizationContext.Current;
var queue = new MessageQueue(@".\Private$\MessageQueue");
queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string)
});
queue.ReceiveCompleted += (sender, e) =>
{
var msg = queue.EndReceive(e.AsyncResult);
string msgVal = (string)msg.Body;
context.Send(_ =>
{
richTextBox1.Text += Environment.NewLine + "MessageQueue
Read Val: " + msgVal;
}, null);
queue.BeginReceive(); // 继续监听
};
queue.BeginReceive();
★
⚠️ 注意:需确保队列存在,且客户端与服务端使用相同的格式化器。
3. 命名管道(Named Pipes)
位于 System.IO.Pipes 命名空间,支持本地或跨网络通信(需配置权限)。
服务端
var server = new NamedPipeServerStream("ProcessCommunicationPipe",
PipeDirection.InOut, 10, PipeTransmissionMode.Message,
PipeOptions.Asynchronous);
await server.WaitForConnectionAsync();
// 接收客户端消息
byte[] buffer = newbyte[1024];
int bytesRead = await server.ReadAsync(buffer, 0,
buffer.Length);
string msg = Encoding.UTF8.GetString(buffer, 0, bytesRead);
richTextBox1.Text += Environment.NewLine + "Server Receive Val:
" + msg;
// 发送消息到客户端
byte[] data = Encoding.UTF8.GetBytes(textBox1.Text);
await server.WriteAsync(data, 0, data.Length);
richTextBox1.Text += Environment.NewLine + "Server Send Val: " +
textBox1.Text;
客户端
var client = new NamedPipeClientStream(".", "ProcessCommunicationPipe",
PipeDirection.InOut, PipeOptions.Asynchronous);
await client.ConnectAsync();
// 接收服务端消息
byte[] buffer = newbyte[1024];
int bytesRead = await client.ReadAsync(buffer, 0,
buffer.Length);
string msg = Encoding.UTF8.GetString(buffer, 0, bytesRead);
richTextBox1.Text += Environment.NewLine + "Client Receive Val:
" + msg;
// 发送消息到服务端
byte[] data = Encoding.UTF8.GetBytes(textBox1.Text);
await client.WriteAsync(data, 0, data.Length);
richTextBox1.Text += Environment.NewLine + "Client Send Val: " +
textBox1.Text;
★
💡 建议使用 async/await 替代 ContinueWith,代码更清晰。
4. 匿名管道(Anonymous Pipes)
仅适用于父子进程通信,不支持网络,且为单向通信。
服务端(父进程)
var server = new AnonymousPipeServerStream(PipeDirection.In,
HandleInheritability.Inheritable);
var clientProcess = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = @"E:\...\ProcessCommunicationClient.exe",
Arguments = server.GetClientHandleAsString(),
UseShellExecute = false
}
};
clientProcess.Start();
server.DisposeLocalCopyOfClientHandle(); // 重要!
byte[] buffer = newbyte[1024];
int bytesRead = await server.ReadAsync(buffer, 0,
buffer.Length);
string msg = Encoding.UTF8.GetString(buffer, 0, bytesRead);
richTextBox1.Text += Environment.NewLine + "匿名 Server Receive Val: " + msg;
客户端(子进程)
// Program.Main(string[] args)
var client = new AnonymousPipeClientStream(PipeDirection.Out,
args[0]);
byte[] data = Encoding.UTF8.GetBytes(textBox2.Text);
await client.WriteAsync(data, 0, data.Length);
richTextBox1.Text += Environment.NewLine + "匿名 Client Send Val: " + textBox2.Text;
5–7. .NET Remoting(IPC / HTTP / TCP)
★
⚠️ 警告:.NET Remoting 已在 .NET Core 中移除,仅适用于 .NET Framework。
三者用法高度一致,仅通道类型不同。
通用服务对象(需继承 MarshalByRefObject)
public class ProcessCommunicationIpc : MarshalByRefObject
{
public string Name { get; private set;
}
public void SetName(string name) =>
Name = name;
}
IPC 服务端
var channel = new IpcChannel("127.0.0.1:8081");
ChannelServices.RegisterChannel(channel, true);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(ProcessCommunicationIpc), "Ipc.rem",
WellKnownObjectMode.Singleton);
IPC 客户端
var channel = new IpcChannel();
ChannelServices.RegisterChannel(channel, true);
var obj = new ProcessCommunicationIpc(); // 透明代理
obj.SetName(textBox3.Text);
服务端读取(轮询或事件)
var proxy =
(ProcessCommunicationIpc)Activator.GetObject(
typeof(ProcessCommunicationIpc), "ipc://127.0.0.1:8081/Ipc.rem");
string name = proxy.Name;
★
HTTP 和 TCP 仅需将 IpcChannel 替换为 HttpChannel/TcpChannel,URL 改为 http://... 或 tcp://...。
8. Socket 通信
最通用的通信方式,支持跨平台、跨网络。
服务端
var server = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Loopback, 8084));
server.Listen(10);
server.BeginAccept(AcceptCallback, server);
void AcceptCallback(IAsyncResult ar)
{
var serverSocket = (Socket)ar.AsyncState;
var client = serverSocket.EndAccept(ar);
// 启动接收线程
var buffer = newbyte[1024];
client.BeginReceive(buffer, 0, buffer.Length,
SocketFlags.None, ReceiveCallback, client);
serverSocket.BeginAccept(AcceptCallback, serverSocket);
}
void ReceiveCallback(IAsyncResult ar)
{
var client = (Socket)ar.AsyncState;
int bytesRead = client.EndReceive(ar);
string msg = Encoding.UTF8.GetString(buffer, 0,
bytesRead);
// 更新 UI
}
客户端
var client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
await client.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 8084));
// 发送
byte[] data = Encoding.UTF8.GetBytes(textBox6.Text);
await client.SendAsync(data, SocketFlags.None);
// 接收
byte[] buffer = new byte[1024];
int bytesRead = await client.ReceiveAsync(buffer,
SocketFlags.None);
string msg = Encoding.UTF8.GetString(buffer, 0, bytesRead);
9. Win32 API:SendMessage
适用于 Windows 窗体应用,通过窗口消息传递数据。
服务端(重写 WndProc)
protected override void WndProc(ref Message
m)
{
const int WM_CUSTOM = 0x1050;
if (m.Msg == WM_CUSTOM)
{
int wParam = (int)m.WParam;
int lParam = (int)m.LParam;
richTextBox1.Text += $"\nWin32 Msg: {wParam}, {lParam}";
}
base.WndProc(ref m);
}
客户端(发送消息)
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg,
IntPtr wParam, IntPtr lParam);
var process = Process.GetProcessesByName("ProcessCommunication").FirstOrDefault();
if (process?.MainWindowHandle != IntPtr.Zero)
{
SendMessage(process.MainWindowHandle, 0x1050, (IntPtr)10,
(IntPtr)20);
}
★
💡 可通过 Marshal 传递结构体,但需注意内存安全。
10. Mutex(互斥体)
用于进程间同步,确保同一时间仅一个进程访问临界区。
服务端 & 客户端(相同代码)
var mutex = new Mutex(false, "Global\\ProcessCommunicationMutex");
Task.Run(() =>
{
while (true)
{
mutex.WaitOne(); // 进入临界区
// 更新 UI
mutex.ReleaseMutex(); // 释放
Thread.Sleep(1000);
}
});
★
🔒 建议使用 Global\ 前缀确保跨会话可见(尤其在 Windows 服务中)。
结语
本文介绍了 C# 中 10 种多进程通信方式,涵盖共享内存、管道、消息队列、Remoting、Socket、Win32 API 和同步原语。每种方式各有适用场景:
- 高性能本地通信:共享内存、命名管道;
- 可靠异步通信:MSMQ;
- 通用网络通信:Socket;
- 简单同步控制:Mutex;
- 遗留系统集成:.NET Remoting(慎用)。
![]() |
Austin Liu 刘恒辉
Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com 欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。 |




浙公网安备 33010602011771号