命名管道(Named Pipes)深度解析(C#—C++应用间交互)
创作时间:
作者:
@小白创作中心
命名管道(Named Pipes)深度解析(C#—C++应用间交互)
引用
1
来源
1.
https://www.cnblogs.com/Firepad-magic/p/18741533
命名管道(Named Pipes)是Windows系统中一种进程间通信(IPC)机制,支持跨进程甚至跨网络的双向数据流传输。本文将从核心概念、C#实现模型、基础代码示例、高级特性与最佳实践等多个维度,深入解析命名管道的使用方法和应用场景。
一、核心概念
命名管道(Named Pipes)是Windows系统中一种进程间通信(IPC)机制,支持跨进程甚至跨网络的双向数据流传输。其核心特点如下:
- 命名唯一性:通过全局唯一的管道名称(如
\\.\pipe\MyPipe)标识通信端点。 - 双工通信:支持同步/异步的读写操作,服务端与客户端可同时收发数据。
- 安全控制:可设置ACL(访问控制列表),限制特定用户或进程的访问权限。
二、C#实现模型
在C#中,通过 System.IO.Pipes 命名空间实现,核心类为:
NamedPipeServerStream:服务端管道,监听并接受客户端连接。NamedPipeClientStream:客户端管道,主动连接服务端。
通信流程
服务端创建管道 → 等待客户端连接 → 客户端连接管道 → 数据交换
三、基础代码示例
1. 服务端实现(接收数据)
using System.IO.Pipes;
using System.Text;
// 服务端代码
var pipeName = "UnityDataPipe";
using (var server = new NamedPipeServerStream(
pipeName,
PipeDirection.InOut, // 双向通信
maxNumberOfServerInstances: 1,
PipeTransmissionMode.Message)) // 按消息分块
{
Console.WriteLine("等待客户端连接...");
server.WaitForConnection();
// 读取数据
byte[] buffer = new byte[1024];
int bytesRead = server.Read(buffer, 0, buffer.Length);
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine($"收到消息: {message}");
// 发送响应
byte[] response = Encoding.UTF8.GetBytes("ACK");
server.Write(response, 0, response.Length);
}
2. 客户端实现(发送数据)
using (var client = new NamedPipeClientStream(
".",
"UnityDataPipe",
PipeDirection.InOut))
{
client.Connect(3000); // 超时3秒
// 发送数据
string message = "点云数据路径: D:/data.pcd";
byte[] data = Encoding.UTF8.GetBytes(message);
client.Write(data, 0, data.Length);
// 读取响应
byte[] response = new byte[256];
int bytesRead = client.Read(response, 0, response.Length);
Console.WriteLine($"服务端响应: {Encoding.UTF8.GetString(response, 0, bytesRead)}");
}
3. Unity端与C++应用通信
C#服务端
using System;
using System.IO;
using UnityEngine;
using System.IO.Pipes;
using System.Threading;
using System.Text;
using System.Threading.Tasks;
public class NamedPathPipeServer
{
// 配置参数
public string pipeName = "UnityFilePathPipe";
public int bufferSize = 4096; // 路径字符串通常较短
private NamedPipeServerStream _server;
private CancellationTokenSource _cts;
private string _receivedPath = null;
private object _pathLock = new object();
public void Start() => StartServer();
public void OnDestroy() => StopServer();
public void OnApplicationQuit() => StopServer();
// 启动服务端
private void StartServer()
{
_cts = new CancellationTokenSource();
Task.Run(() => ListenForPaths(_cts.Token), _cts.Token);
}
// 监听循环
private async Task ListenForPaths(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
try
{
using (_server = new NamedPipeServerStream(
pipeName,
PipeDirection.In,
1,
PipeTransmissionMode.Message, // 按消息分块
PipeOptions.Asynchronous))
{
await _server.WaitForConnectionAsync(token);
byte[] buffer = new byte[bufferSize];
int bytesRead = await _server.ReadAsync(buffer, 0, buffer.Length, token);
string path = Encoding.UTF8.GetString(buffer, 0, bytesRead);
lock (_pathLock)
{
_receivedPath = path;
}
}
}
catch (Exception e)
{
Console.WriteLine($"管道异常: {e.Message}");
}
}
}
// Unity主线程处理
public void Update()
{
string pathToLoad = null;
lock (_pathLock)
{
if (!string.IsNullOrEmpty(_receivedPath))
{
pathToLoad = _receivedPath;
_receivedPath = null;
}
}
if (pathToLoad != null)
{
Debug.Log($"收到点云路径: {pathToLoad}");
LoadPointCloudFromPath(pathToLoad);
}
}
private void LoadPointCloudFromPath(string filePath)
{
// 此处实现文件读取逻辑(示例伪代码)
if (File.Exists(filePath))
{
byte[] data = File.ReadAllBytes(filePath);
Vector3[] points = ParsePointCloud(data); // 解析为坐标数组
RenderPointCloud(points);
}
else
{
Debug.LogError($"文件不存在: {filePath}");
}
}
// 解析点云
private Vector3[] ParsePointCloud(byte[] data)
{
return new Vector3[0]; // 示例代码,实际解析请根据文件格式自行实现
}
// 渲染点云
private void RenderPointCloud(Vector3[] points)
{
// 此处实现渲染逻辑(示例伪代码)
foreach (var point in points)
{
Debug.DrawRay(point, Vector3.up, Color.red, 0.1f, false);
}
}
private void StopServer()
{
_cts?.Cancel();
_server?.Close();
}
}
C++客户端
void SendPathToUnity(const std::string& path) {
HANDLE hPipe = CreateFileA(
"\\\\.\\pipe\\UnityFilePathPipe",
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (hPipe == INVALID_HANDLE_VALUE) {
// 错误处理
return;
}
DWORD bytesWritten;
WriteFile(hPipe, path.c_str(), path.size(), &bytesWritten, NULL);
CloseHandle(hPipe);
}
四、高级特性与最佳实践
1. 异步通信模式
// 服务端异步等待连接
await server.WaitForConnectionAsync();
// 异步读写
byte[] buffer = new byte[4096];
int bytesRead = await server.ReadAsync(buffer, 0, buffer.Length);
await server.WriteAsync(responseBuffer, 0, responseBuffer.Length);
2. 多客户端支持
// 服务端循环处理多个客户端
while (true)
{
using (var server = new NamedPipeServerStream(...))
{
await server.WaitForConnectionAsync();
Task.Run(() => HandleClient(server)); // 为每个客户端创建独立任务
}
}
3. 消息分帧协议
- 长度前缀法:发送数据前附加4字节长度头。
// 发送端
byte[] data = ...;
byte[] lengthHeader = BitConverter.GetBytes(data.Length);
client.Write(lengthHeader, 0, 4);
client.Write(data, 0, data.Length);
// 接收端
byte[] header = new byte[4];
await stream.ReadAsync(header, 0, 4);
int length = BitConverter.ToInt32(header, 0);
byte[] payload = new byte[length];
await stream.ReadAsync(payload, 0, length);
4. 安全性控制
// 设置管道权限(仅允许当前用户)
var pipeSecurity = new PipeSecurity();
pipeSecurity.AddAccessRule(new PipeAccessRule(
WindowsIdentity.GetCurrent().User,
PipeAccessRights.ReadWrite,
AccessControlType.Allow));
var server = new NamedPipeServerStream(
pipeName,
PipeDirection.InOut,
1,
PipeTransmissionMode.Message,
PipeOptions.None,
4096, 4096,
pipeSecurity);
五、性能优化策略
优化方向 | 实现方法 |
|---|---|
缓冲区管理 | 使用固定大小缓冲区池(避免频繁内存分配) |
批量传输 | 合并小数据包,减少系统调用次数(如每100ms发送一次数据) |
零拷贝技术 | 通过MemoryMappedFile共享内存区域(需配合事件同步) |
多线程处理 | 分离读写线程,利用BlockingCollection实现生产者-消费者模型 |
六、适用场景与局限性
适用场景
- Unity与本地C++程序实时数据交换
- 需要严格权限控制的内部进程通信
- 高吞吐量但低延迟的本地IPC需求
局限性
- 跨平台限制:原生命名管道主要支持Windows,Linux/macOS需通过第三方库(如
Mono.Posix) - 网络延迟:跨网络通信时性能低于专用网络协议(如gRPC)
七、与其他IPC机制对比
机制 | 延迟 | 吞吐量 | 跨平台 | 复杂度 |
|---|---|---|---|---|
命名管道 | 低 | 高 | 弱 | 中 |
TCP Socket | 中 | 中 | 强 | 高 |
共享内存 | 极低 | 极高 | 弱 | 高 |
gRPC | 中 | 高 | 强 | 低 |
通过合理使用命名管道,开发者可在C#项目中实现高效可靠的本地进程通信,尤其适用于需要高实时性的数据交换场景。
📚 扩展学习资源
- 微软官方文档:NamedPipeServerStream
本文原文来自Cnblogs
热门推荐
北京三日游攻略:精华景点与地道体验全攻略
马拉松训练精细化的技巧(如何通过精细化训练提高马拉松成绩)
瓦西里·扎耶采夫:苏联的传奇狙击手
全飞秒和半飞秒的区别有哪些?郑州近视手术专家孙彪解答
如何让孩子们拥抱课间自由?要“像重视课堂一样重视课间”
安卓王者荣耀怎么不卡?这份流畅运行攻略请收好
【云计算】公有云、私有云、混合云、社区云、多云
心学问心理教育,家长如何帮助孩子培养高效的学习习惯
混动车主注意!2025年3月起年检新规实施,这些变化需提前了解
即食燕麦升糖快吗?医生专业解答
表情包项目是否能持久盈利,市场需求与操作模式分析
什么样的人,一定要远离situationship?
郑州发力跨境电商“黄金赛道”
教师工资管理系统怎样生成课时费明细报表
去听听雨打芭蕉的音韵美
学校发生食品安全事故,责任谁来承担?(附案例)
Win11补丁更新导致鼠标异常如何解决
“人造太阳”:能源自由的愿景
大模型在医疗实践中的应用
属兔人的一生命运 生肖属兔的性格和脾气
川渝携手升级长江黄金水道 “含金量”走高推动“双圈”更具竞争力
黄金价格暴涨之下的“金条大迁徙”:伦敦库存告急,纽约金库爆满
应科院创新智慧出行科技 闪耀香港秋季电子产品展
高考前实用的冲刺方法与策略
咬定研发创新不放松的深圳企业,如何向“新”攀高
成为高效的学习者:掌握学习策略,突破学习瓶颈
CBA最新消息!袁照耀致郭艾伦受伤,北京签纳塔尔,新疆签哈雷尔
听我一句劝,农村建房,不仅仅是风水,还有科学
如何轻松打造高级感家居?这些轻奢元素你一定不能错过
中国移动5G用户突破5亿:稳坐通信行业半壁江山