12

目前我正在 Windows 上开发一个多进程桌面应用程序。此应用程序将是一个收缩包装的应用程序,将部署在世界各地的客户端机器上。虽然我们可以为机器制定广泛的规格 - 例如带有 .Net 4.0 CF 的 Windows XP SP3,但我们无法控制它们并且我们不能对它们的配置过于具体 - 例如我们不能指定机器必须具有支持 cuda 1.4 的图形处理器等等

其中一些进程是托管的(.Net 4.0),而其他进程是非托管的(C++ Win32)。进程需要共享数据。我迄今为止评估的选项是

  • Tcp 套接字
  • 命名管道

管道的性能似乎稍好一些,但对于我们的需要 - 两者的性能都是可以接受的。套接字为我们提供了未来跨越机器(和操作系统——我们希望最终支持非微软操作系统)边界的灵活性,因此我们更喜欢使用套接字。

但是 - 我主要担心的是 - 如果我们使用 Tcp 套接字 - 我们可能会遇到防火墙问题吗?是否有其他人部署了使用 TCP 进行 IPC 的桌面应用程序/程序并遇到问题?如果是这样 - 什么样的?

我知道这是一个相当开放的问题,我很乐意重新措辞。但我真的很想知道我们可能会遇到什么样的潜在问题。

编辑:为了更亮一点——我们只传输一些 POD、整数、浮点数和字符串。我们已经建立了一个抽象层,它提供了两种范式——请求/响应和订阅。传输层已经被抽象出来,目前我们有两种实现方式——基于管道的和基于 TCP 的。

4

3 回答 3

8

管道的性能在快速 LAN 上通常更好,但 TCP 在较慢的网络或 WAN 上通常更好。请参阅下面的 msdn 点。

TPC 也更具可配置性。关于防火墙,它们允许您打开/关闭通信端口。如果这不是一个选项或问题,替代方案将是 http(REST/json、Web 服务、xml rpc 等),但您必须考虑 http 开销是否可以接受。确保您使用真实世界的数据集进行尝试(在测试中传递琐碎的数据会使开销看起来不合理,这对于真实世界的数据集来说是非常合理的)。

来自msdn的其他一些信息:

在快速局域网 (LAN) 环境中,传输控制协议/Internet 协议 (TCP/IP) 套接字和命名管道客户端在性能方面具有可比性。但是,TCP/IP 套接字和命名管道客户端之间的性能差异在较慢的网络中变得明显,例如跨广域网 (WAN) 或拨号网络。这是因为进程间通信 (IPC) 机制在对等点之间进行通信的方式不同。

对于命名管道,网络通信通常更具交互性。一个对等点不会发送数据,直到另一个对等点使用读取命令请求它。网络读取通常涉及一系列 peek 命名管道消息,然后才开始读取数据。在慢速网络中,这些成本可能非常高,并导致网络流量过多,进而影响其他网络客户端。

澄清您是在谈论本地管道还是网络管道也很重要。如果服务器应用程序在运行 Microsoft® SQL Server™ 2000 实例的计算机上本地运行,则可以选择本地命名管道协议。本地命名管道在内核模式下运行并且速度非常快。

对于 TCP/IP 套接字,数据传输更加流畅,开销也更少。数据传输还可以利用 TCP/IP 套接字性能增强机制,例如窗口化、延迟确认等,这在慢速网络中非常有用。根据应用程序的类型,这种性能差异可能很大。

TCP/IP 套接字还支持积压队列,与在您尝试连接到 SQL Server 时可能导致管道繁忙错误的命名管道相比,它可以提供有限的平滑效果。

> 一般来说,在速度较慢的 LAN、WAN 或拨号网络中,套接字是首选,而当网络速度不是问题时,命名管道可能是更好的选择,因为它提供了更多的功能、易用性和配置选项。

有关 TCP/IP 的详细信息,请参阅 Microsoft Windows NT® 文档。

于 2012-06-04T20:55:06.500 回答
2

如果您需要模拟命名管道客户端的安全凭证,那么实际上只有一种选择 :) 命名管道也有更好的名称(尽管 DNS SRV 记录也可以为 TCP 端口提供这些名称)。

否则,差别不大。两者都将数据视为字节流,让您自己负责查找消息边界。命名管道具有为您保留消息边界的附加选项,但请注意,您必须在消息模式下创建管道并显式设置读取模式。

于 2012-06-04T21:16:03.300 回答
1

如果我正确理解您的要求,您需要在同一台计算机上运行的进程之间进行通信。这些进程可能都在交互登录的用户的相同安全上下文中运行。

在这种情况下,我应该提到解决方案的不同方面。一个问题是在应用程序之间共享数据。另一个问题是协议,它定义了如何访问和修改公共数据以及进程之间的通信如何发生。例如,您可以让一个进程提供数据,而另一个进程订阅数据。另一种情况:您可以拥有所有应用程序都可以读取或修改的公共数据,您只需确保没有人同时修改共享数据,或者在另一个修改数据时没有人访问数据。当然,它可能是许多其他不同的通信场景。

在这方面,我会建议您在问题中未包含的其他两个选项:

  • 使用内存映射文件(请参见此处此处
  • COM接口的使用

这两种方式都可以在 .NET 和非托管 C++ 中很好地实现。从性能的角度来看,使用内存映射文件是最好的方法。如果您创建不与某些物理文件关联的视图,您将只有可在进程之间使用的公共内存。您可以另外使用 Mutex 或 Event 来控制多个应用程序不会同时使用内存。

在最简单的场景中,您甚至可以使用C++ 中的#pragma data_seg将一些数据放置在 DLL 的命名部分中,并使用/SECTION选项(如/SECTION:.MYSEC,RWS)使数据共享。您可以在所有 .NET 应用程序和所有非托管 C++ 应用程序中使用 DLL 来访问公共数据。在这种方式下,您将拥有访问公共数据的简单方法。

如果您需要一些更复杂的通信场景,那么在 C++/.NET 中使用 COM 接口的方法可能是最佳选择。如果我向您推荐这篇文章,该文章逐步描述了如何仅在 .NET 中使用 COM 接口实现 Primary Interop Assembly,并在 .NET 和 C++ COM 中使用它进行通信。

于 2012-06-05T12:09:28.393 回答