C# 套接字与管道

本文关键字:管道 套接字 | 更新日期: 2023-09-27 18:36:18

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

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

  • Tcp 插座
  • 命名管道

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

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

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

编辑:为了投射更多的光 - 我们只传输一些 POD、整数、浮点数和字符串。我们构建了一个抽象层,提供 2 种范式 - 请求/响应和订阅 .传输层已被抽象化,目前我们有两种实现 - 基于管道和基于 TCP。

C# 套接字与管道

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

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

来自 msdn 的其他一些信息:

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

对于命名管道,网络通信通常更多 互动。对等方不会发送数据,直到另一个对等方请求 使用读取命令。网络读取通常涉及一系列 在开始读取数据之前,速览命名管道消息。这些可以 在慢速网络中非常昂贵,并导致过多的网络流量, 这反过来又会影响其他网络客户端。

澄清您是否在谈论本地管道也很重要 或网络管道。如果服务器应用程序在本地运行 运行 SQL Server™ 2000 实例Microsoft®计算机,本地 命名管道协议是一种选择。本地命名管道在内核中运行 模式,并且速度极快。

对于 TCP/IP 套接字,数据传输更加简化,并且具有 开销更少。数据传输也可以利用 TCP/IP 套接字性能增强机制,如窗口化、延迟 致谢等等,这在缓慢的情况下可能非常有益 网络。根据应用程序的类型,此类性能 差异可能很大。

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

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

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

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

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

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

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

在这个方面,我建议您另外两个选项,您没有包含在您的问题中:

  • 使用情况内存映射文件(请参阅此处和此处)
  • COM 接口的使用

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

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

如果需要一些更复杂的通信方案,则在 C++/.NET 中使用 COM 接口的方法可能是最佳选择。在这种情况下,我会向您推荐这篇文章,该文章逐步描述了如何在 .NET 中仅使用 COM 接口实现主互操作程序集,并在 .NET 和 C++ COM 中使用它进行通信。