C# 如何正确关闭客户端代理(远程主机强制关闭了现有连接)?
在把问题读到最后之前,请不要重复关闭;我已经在谷歌上搜索了几个小时没有成功C# 如何正确关闭客户端代理(远程主机强制关闭了现有连接)?,c#,.net,wcf,tcp,nettcpbinding,C#,.net,Wcf,Tcp,Nettcpbinding,在把问题读到最后之前,请不要重复关闭;我已经在谷歌上搜索了几个小时没有成功 编辑:现在我确信这与WCF缓存打开的TCP连接(连接池)的方式有关。请看问题结尾处的编辑5 我基本上有一个WCF服务,它使用netTcpBinding配置。即使我优雅地关闭了客户端代理(请参见下面的代码),服务器也会始终记录“System.Net.Sockets.SocketException(0x80004005):远程主机强制关闭了现有连接” 我已经将问题缩小到我能写的最基本的WCF示例。每次关闭客户端应用程序时
编辑:现在我确信这与WCF缓存打开的TCP连接(连接池)的方式有关。请看问题结尾处的编辑5
我基本上有一个WCF服务,它使用
netTcpBinding
配置。即使我优雅地关闭了客户端代理(请参见下面的代码),服务器也会始终记录“System.Net.Sockets.SocketException(0x80004005):远程主机强制关闭了现有连接”
我已经将问题缩小到我能写的最基本的WCF示例。每次关闭客户端应用程序时,WCF跟踪生成的日志中都会出现异常。不过,我自己的代码中没有任何异常,这意味着它按预期工作,我无法调试任何东西来查看WCF在我的日志中添加错误的原因
服务接口/实现:
[ServiceContract]
public interface IService1
{
[OperationContract]
string DoWork();
}
...
public class Service1 : IService1
{
public string DoWork()
{
return "12";
}
}
服务器端配置:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="WebApplication1.Service1">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="netTcpEndpointBinding" contract="WebApplication1.IService1" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="netTcpEndpointBinding">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IService1">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost/WebApplication1/Service1.svc"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IService1"
contract="ServiceReference1.IService1" name="NetTcpBinding_IService1" />
</client>
</system.serviceModel>
</configuration>
非常感谢
编辑2:在IIS中托管服务或在Windows服务中自托管服务时,我遇到了相同的问题
编辑3:这里有一个完整的例子来重现这个问题:
编辑4:
我试图通过WCF为我建立的TCP连接来监控引擎盖下实际发生的事情
关闭客户端代理后,我仍然看到与服务器的TCP连接已打开:
我假设这与要缓存以供将来重用的TCP连接(即连接池)有关,因为打开到服务器的新连接(在第一个客户端代理关闭后)不会创建新的TCP连接。如果我调用Console.WriteLine(newtest().TestTask().Result)代码>在我的应用程序中两次,我仍然只看到一个打开的TCP连接
我还注意到,如果在关闭客户端通道后等待太长时间,则此连接会因超时而终止
编辑5:好的,我在MSDN上找到了关于连接池的文档:
NetTcpBinding使用基于服务的TCP连接池
主机DNS名称和服务正在侦听的端口号。这
当客户端在上调用不同的服务时效果良好
不同的端口或服务托管在单个进程中并共享
港口。如果单个客户端调用共享一个端口的多个服务
托管在不同进程中,或者托管在客户端WAS/IIS中
侧池可能会导致无法连接到服务a的问题
重新用于服务B,导致引发异常
连接中止,并创建了一个新通道。为了避免这个问题,,
使用CustomBinding并指定不同的
客户端上每个服务的ConnectionPoolSettings.GroupName
与……沟通
所以现在我的问题是:如果这是一种正常行为,我该怎么做才能防止日志被所有这些异常污染?我怀疑try块中的return命令导致执行跳过finally块,导致连接保持打开状态,直到客户端关闭导致异常。这可能吗?您是否确保已执行最终块?编辑
好啊我可以用你的代码重现这个问题。好消息是我也偶然发现了一种不复制它的方法。我认为您的代码中没有任何问题。我认为正在记录错误,因为您正在VS中的调试器中运行它;当调试器关闭服务导致错误被记录时
按照以下步骤进行操作,看看是否不再出现错误(这对我来说每次都非常有效):
右键单击服务项目并选择调试>启动新实例
右键单击控制台应用程序并选择调试>启动新实例
运行控制台直到完成
检查您的日志文件
使用WCF测试客户端窗口而不是调试器停止按钮停止服务
检查您的日志文件
下面是我做上述步骤的冲击波视频链接:
最初的
你发布的代码在我的系统上运行良好。我没有收到任何日志中的错误。顺便说一句,我将完全摆脱catch块,因为它除了重新引用异常之外什么也不做。然后我会像下面这样写最后一个块。我认为它使代码更清晰,并向读者传达了这样一种想法:如果抛出异常,您将什么也不做
Service1Client proxy = null;
try
{
Console.WriteLine("Calling service");
proxy = new Service1Client();
return await proxy.DoWorkAsync();
}
finally
{
if (proxy != null)
{
if (proxy.State == CommunicationState.Faulted)
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
else
{
Console.WriteLine("Closing client");
proxy.Close();
}
}
}
要解决此错误,只需关闭通道工厂即可
private async Task<string> TestTask()
{
Service1Client proxy = null;
try
{
Console.WriteLine("Calling service");
proxy = new Service1Client();
return await proxy.DoWorkAsync();
}
finally
{
if (proxy.State != System.ServiceModel.CommunicationState.Faulted)
{
Console.WriteLine("Closing client");
proxy.ChannelFactory.Close();
proxy.Close();
}
else
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
}
}
private异步任务TestTask()
{
Service1Client proxy=null;
尝试
{
Console.WriteLine(“呼叫服务”);
proxy=newservice1client();
返回wait-proxy.doworksync();
}
最后
{
if(proxy.State!=System.ServiceModel.CommunicationState.Faulted)
{
Console.WriteLine(“关闭客户”);
proxy.ChannelFactory.Close();
proxy.Close();
}
其他的
{
Console.WriteLine(“正在中止客户端”);
proxy.Abort();
}
}
}
这可能与控制台应用程序中的async/Wait有关吗?我记得在某个地方读到,由于线程问题,async/await不适合控制台应用程序。尝试使用非异步方法执行此操作,看看是否会出现相同的问题。@Tim我现在无法测试,但是的,控制台应用程序和GUI应用程序之间存在差异:线程模型,即线程池与主UI线程。我不认为问题来自这里,因为这是一个使用WPF构建的实际应用程序的简化示例。第一,如果您还没有启用WCF跟踪。第二,我想知道是否最终Service1Client proxy = null;
try
{
Console.WriteLine("Calling service");
proxy = new Service1Client();
return await proxy.DoWorkAsync();
}
finally
{
if (proxy != null)
{
if (proxy.State == CommunicationState.Faulted)
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
else
{
Console.WriteLine("Closing client");
proxy.Close();
}
}
}
private async Task<string> TestTask()
{
Service1Client proxy = null;
try
{
Console.WriteLine("Calling service");
proxy = new Service1Client();
return await proxy.DoWorkAsync();
}
finally
{
if (proxy.State != System.ServiceModel.CommunicationState.Faulted)
{
Console.WriteLine("Closing client");
proxy.ChannelFactory.Close();
proxy.Close();
}
else
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
}
}