下面的方法(我希望它没有犯任何错误,同时大大简化了这篇文章)正在正常工作,并通过net.tcp协议使用流传输模式进行设置。问题是性能明显差于通过IIS通过http下载相同的文件。为什么会这样,我可以改变什么来改善性能呢?
Stream WebSiteStreamedServiceContract.DownloadFile( string filePath ) {
return File.OpenRead( filePath );
}
最后,WCF是否负责妥善处理我的流,并且它在这方面做得好吗?如果没有,我应该做什么呢?
谢谢。
经过8个月的处理这个问题,其中3个与微软,这里是解决方案。简短的回答是服务器端(发送大文件的一方)需要使用以下内容进行绑定:
<customBinding>
<binding name="custom_tcp">
<binaryMessageEncoding />
<tcpTransport connectionBufferSize="256192" maxOutputDelay="00:00:30" transferMode="Streamed">
</tcpTransport>
</binding>
</customBinding>
这里的关键是connectionBufferSize属性。可能需要设置其他几个属性(maxReceivedMessageSize等),但connectionBufferSize是罪魁祸首。
服务器端不需要更改代码。
客户端不需要更改代码。
无需在客户端更改配置。
这是一个很长的答案:
我一直怀疑net.tcp over WCF的原因是因为它经常发送小块信息而不是更频繁地发送大量信息,这使得它在高延迟网络(互联网)上表现不佳。事实证明这是真的,但到达那里是一条漫长的道路。
netTcpBinding上有几个属性听起来很有希望:maxBufferSize是最明显的,而maxBytesPerRead和其他人听起来也很有希望。除此之外,还可以创建比原始问题更复杂的流 - 您也可以在客户端和服务器端指定缓冲区大小。问题是这些都没有任何影响。一旦你使用netTcpBinding,你就会受到冲击。
原因是在netTcpBinding上调整maxBufferSize会调整协议层上的缓冲区。但是你无法对netTcpBinding做任何调整底层传输层。这就是为什么我们失败了很久才取得进展。
自定义绑定解决了这个问题,因为增加传输层上的connectionBufferSize会增加一次发送的信息量,因此传输更不容易受到延迟的影响。
在解决这个问题时,我注意到maxBufferSize和maxBytesPerRead确实对低延迟网络(和本地)产生了性能影响。 Microsoft告诉我,maxBufferSize和connectionBufferSize是独立的,并且它们的值的所有组合(彼此相等,maxBufferSize大于connectionBufferSize,maxBufferSize小于connectionBufferSize)是有效的。我们成功使用了65536字节的maxBufferSize和maxBytesPerRead。但是,这对高延迟网络性能(原始问题)的影响非常小。
如果您想知道maxOutputDelay的用途,那么它是在框架抛出IO异常之前分配给填充连接缓冲区的时间量。因为我们增加了缓冲区大小,所以我们还增加了分配给缓冲区的时间。
使用此解决方案,我们的性能提高了约400%,现在略好于IIS。还有其他一些因素影响IIS上的HTTP和WCF over net.tcp(以及WCF over http)的相对和绝对性能,但这是我们的经验。
我不知道你的第一个问题的答案(我认为你需要提供更多代码来展示你对你的两个测试做了什么),但是你关于流的处理的第二个问题,答案是你需要自己做。
Here is an excellent blog entry有一些很好的代码就是为了这个目的。
我接受了@ Greg-Smalter的建议并使用反射改变ConnectionBufferSize
上的NetTcpBinding
,这解决了我的问题。流媒体大文件现在快速尖叫。这是代码。
var transport = binding.GetType().GetField("transport", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(binding);
transport?.GetType().GetProperty("ConnectionBufferSize", BindingFlags.Public | BindingFlags.Instance)?.SetValue(transport, 256192);
这是另一种方法,无需处理反射。只需将NetTcpBinding
包装成CustomBinding
。
var binding = new CustomBinding(new NetTcpBinding
{
MaxReceivedMessageSize = 2147483647,
MaxBufferSize = 2147483647,
MaxBufferPoolSize = 2147483647,
ReceiveTimeout = new TimeSpan(4, 1, 0),
OpenTimeout = new TimeSpan(4, 1, 0),
SendTimeout = new TimeSpan(4, 1, 0),
CloseTimeout = new TimeSpan(4, 1, 0),
ReaderQuotas = XmlDictionaryReaderQuotas.Max,
Security =
{
Mode = SecurityMode.None,
Transport = {ClientCredentialType = TcpClientCredentialType.None}
},
TransferMode = TransferMode.Streamed,
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard
});
binding.Elements.Find<TcpTransportBindingElement>().ConnectionBufferSize = 665600;
以上基于反思的答案对我们有用。如果您需要通过托管的IIS / WCF服务执行此操作;您可以使用魔术配置函数声明来访问Binding来执行此操作:
public static void Configure(ServiceConfiguration config)
{
NetTcpBinding tcpBinding = new NetTcpBinding { /* Configure here */ };
var transport = tcpBinding.GetType().GetField("transport", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(tcpBinding);
transport?.GetType().GetProperty("ConnectionBufferSize", BindingFlags.Public | BindingFlags.Instance)?.SetValue(transport, 256192);
ServiceEndpoint se = new ServiceEndpoint(ContractDescription.GetContract(typeof(IService)), tcpBinding , new EndpointAddress("net.tcp://uri.foo/bar.svc"))
{
ListenUri = new Uri("net.tcp://uri.foo/bar.svc")
};
config.AddServiceEndpoint(se);
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
}
感谢您在这篇文章中提供的信息。关于这个问题,没有很多信息。我想添加一些可能对其他人有用的其他细节。
这里的大多数响应似乎表明人们正在使用单个NetTcp端点,或者他们没有在IIS中托管WCF。
如果您在同一个wcf服务中使用多个netTcp端点并在IIS中托管或使用使用WAS的容器,则可能会遇到这些问题。
<windowsStreamSecurity />
所以绑定最终看起来像这样:<binding name="CustomTcpBinding_ServerModelStreamed">
<windowsStreamSecurity />
<binaryMessageEncoding />
<tcpTransport connectionBufferSize="5242880" maxReceivedMessageSize="2147483647" maxBufferSize ="2147483647" transferMode="Streamed" />
</binding>
您不必更改客户端NetTcp配置,当然,如果您没有使用此处未反映的任何其他功能。对于customBinding,节的顺序很重要。 https://docs.microsoft.com/en-us/dotnet/framework/wcf/extending/custom-bindings