WCF – 最快的进程间通信

A具有Web可访问(通过basicHttpBinding)WCF服务,我也希望从同一台机器上的其他.NET服务访问,并尽可能提高性能。 我知道netNamedPipeBinding是理想的,但是想知道什么是最好的配置,我甚至只会与其他.NET进程通信。

例如,我不一定使用像SOAP这样的编码,因为这可能太笨重,而且我不需要与.NET客户端以外的任何其他客户端兼容。 我也认为我不需要任何安全保障。

什么是用于此目的的最佳绑定配置(或任何其他配置)

如您所知 , NetNamedPipeBinding绑定针对同一台机器通信进行了优化:

提供安全可靠的绑定,针对机上通信进行了优化。

参考。 : 系统提供的绑定

在Juval Lowy的书“编程WCF服务”的第一章中,他提供了一个有用的决策活动图,用于选择正确的绑定:

“您应该问自己的第一个问题是您的服务是否需要与非WCF客户端进行交互。如果答案是肯定的,并且客户端是传统的MSMQ客户端,请选择MsmqIntegrationBinding,使您的服务能够通过MSMQ与MSMQ进行互操作。如果您需要与非WCF客户端进行互操作,并且该客户端需要基本的Web服务协议(ASMX Web服务),请选择BasicHttpBinding,它将您的WCF服务公开给外部世界,就好像它是ASMX Web服务一样(也就是WSI基本配置文件。。缺点是您无法利用大多数现代WS- *协议。但是,如果非WCF客户端可以理解这些标准,请选择其中一个WS绑定,例如WSHttpBinding,WSFederationHttpBinding或WSDualHttpBinding。如果您可以假设客户端是WCF客户端,但它需要脱机或断开连接,请选择使用MSMQ传输消息的NetMsmqBinding。如果客户端需要conn 通过通信,但可以跨机器边界调用,选择通过TCP进行通信的NetTcpBinding。 如果客户端与服务位于同一台计算机上,请选择使用命名管道的NetNamedPipeBinding以最大限度地提高性能。 您可以根据其他条件(例如需要回调(WSDualHttpBinding)或联合安全性(WSFederationHttpBinding))来微调绑定选择。“

当然,命名管道运输是最好的选择。

默认情况下,在标准NetNamedPipeBinding上启用使用EncryptAndSign的传输安全性。 你当然希望删除它,因为这样做会加快速度而不会对安全产生任何实际影响,这是我在这里讨论的原因。

我也怀疑,但尚未证实,更改消息编码绑定元素可能会有所帮助。 这是因为默认情况下是WCF专有的“带内字典二进制编码”,它是XML信息集的编码,旨在减少冗余字节,例如打开和关闭元素标签:当涉及网络IO时,这是一个有价值的目标,但是,当消息传输完全在内存中时(如果消息不是太大),可能会浪费CPU工作量。 因此,改变为纯文本编码也可以提高速度。

我知道这是一个非常古老的问题,但它仍然值得回答。 如前所述,命名管道是最快的,您需要禁用安全性,但如果您摆脱数据协定序列化并切换到基于流的传输模式,您将获得最显着的效果。

使用类似这样的绑定配置:

new NetNamedPipeBinding { MaxReceivedMessageSize = 524288000, ReceiveTimeout = TimeSpan.MaxValue, // never timeout SendTimeout = TimeSpan.MaxValue, // never timeout ReaderQuotas = { MaxStringContentLength = 655360000 }, TransferMode = TransferMode.Streamed, Security = new NetNamedPipeSecurity { Mode = NetNamedPipeSecurityMode.None, Transport = new NamedPipeTransportSecurity { ProtectionLevel = ProtectionLevel.None } } } 

像这样定义您的服务消息:

 [MessageContract] public class CallRequestMessage { [MessageHeader] public string Arg1; [MessageHeader] public int ParametersLen; [MessageBodyMember] public Stream Parameters; } [MessageContract] public class CallResponceMessage { [MessageHeader] public int ResultCode; [MessageHeader] public int ResultsLen; [MessageBodyMember] public Stream Results; } [ServiceContract] public interface ILocalServiceAPI { [OperationContract] CallResponceMessage Call(CallRequestMessage message); } 

这种方法的缺点是现在你必须自己序列化你的数据。 我更喜欢将protobuf序列化直接用于MemoryStream。 将此流放入CallRequestMessage.Parameters。

不要忘记在消息头中传输ParametersLen / ResultsLen,因为Stream是无限的(读取时你可能会收到0个字节,但与普通流不同,你应该继续阅读)。