【问题标题】:Named Pipes communication failure between a c# and C programc# 和 C 程序之间的命名管道通信失败
【发布时间】:2015-11-06 15:26:02
【问题描述】:

每个人。我的团队目前正在开发一个涉及两个部分的系统:C# 中的数据组织、UI 等,以及由于性能要求而在 C 中进行大量数字运算。我们正在尝试压缩性能的每一点,所以虽然最初我们使用文件与两个进程通信,但我们正在通过 IPC 通信这两个进程来继续前进。专门命名的管道。传输 C 程序所需数据的 C# 程序的简化版本是这样的:

String pipeName = "some_random_name";
NamedPipeServerStream pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.Out, 2, PipeTransmissionMode.Byte, PipeOptions.None, 0, 4096);
Process someProcess= new Process();
someProcess.StartInfo.FileName = appDirectory + "someProcess.exe";
someProcess.StartInfo.RedirectStandardInput = true;
someProcess.StartInfo.RedirectStandardOutput = true;
someProcess.StartInfo.RedirectStandardError = false;
someProcess.StartInfo.UseShellExecute = false;

someProcess.StartInfo.Arguments = "\\\\.\\pipe\\" + pipeName;
someProcess.Start();
someProcess.PriorityClass = ProcessPriorityClass.RealTime;

pipeServer.WaitForConnection();
pipeServer.Write(BitConverter.GetBytes(lengthOfNextDataSent), 0, 4);
pipeServer.WaitForPipeDrain();

for (i = 0; i < lengthOfNextDataSent; i++){
    byte[] xBytes = BitConverter.GetBytes(SomeOtherIntegerData);
    pipeServer.Write(xBytes , 0, xBytes.Length);
}

而简化的客户端 C 代码是:

fd = open(argv[1], O_RDONLY);
read(fd, &received_length, sizeof(int));
for(i = 0; i < received_length; i++){
    read(fd, integer_array[i], 16);
}
close(fd);

奇怪的是,我能够正确接收(在 C 应用程序中)并解码多达 1820~ 个字节。如果我尝试调用 C# 方法 WaitForPipeDrain 或在写入 1820~ 字节后尝试刷新(在较小的块中,整数大小或更大),则会引发“管道损坏”异常。如果我尝试在一次调用中写入比这更多的字节,则 C 应用程序在读取时会崩溃。

编辑:一个我忘了提的细节。我正在使用 mingw32-64 编译器在类似 cygwin 的环境(特别是 msys2)中编译 C 程序。

你能告诉我我做错了什么吗?

【问题讨论】:

  • 我很确定这不是您正确序列化数据的方式。还有,你是怎么在C程序中分配integer_array[]的?
  • 我只是发送整数。哪种方式是正确的做法?我尝试在 C 中使用 read 方法,使用单个整数作为接收缓冲区,分配为 char * buf 的 char 数组缓冲区; buf = (char *) malloc ( expected_size * sizeof(int) );或者简单地说:char buf[someSize];
  • 如果你读的是整数,为什么不read(fd, ..., sizeof(int)
  • 如果您想要高性能,请将 C 代码置于进程中(在 DLL 中,使用 p/invoke)
  • EOF:这就是我第一次尝试读取整数的方式。有那么一刻,我认为 sizeof 的结果在 c# 和 C 中给了我不同的结果,所以我硬编码了大小。无论 sizeof(int) 如何,行为都是相同的。 Ben:C 代码非常复杂,而且不是线程安全的。因此,当我们尝试在 DLL 中执行多个代码实例时遇到了问题。我们可以修改 C 代码,但由于时间限制,它很大,而且不是一个非常可行的目标。

标签: c# c ipc named-pipes


【解决方案1】:

您忽略了read 调用的返回值,并假设整个缓冲区都有效。

在管道上,你不能忽视这一点。

刚刚在 Raymond Chen 的博客上对此进行了讨论:Changing the conditions under which ReadFile produces fewer bytes than requested,其中讨论了在 POSIX 下(严格来说,它不限制 Win32,但确实设置了 Win32 API 小心满足的期望) 您的假设对普通本地文件有效,但对管道无效。

【讨论】:

  • 我明确地忽略了读取字节的结果,并添加了一个部分读取循环来等待额外的数据。但是,在传输了一定数量的字节后,写入停止了。 C 程序中的读取函数无限期地接收 0 字节,并且 C# 程序在刷新时崩溃,或者在调用“waitForDrain”时挂起。我必须假设这种 IPC 不适用于 mingw32_64 C 和 C# 应用程序?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-15
  • 1970-01-01
  • 2015-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多