在您阅读完问题之前,请不要将其标记为重复;我已经谷歌了几个小时,但没有成功。
编辑:现在我相信这与WCF缓存打开的TCP连接的方式有关(连接池)。请看问题末尾的第5次编辑。
我基本上有一个使用netTcpBinding
配置的WCF服务。即使我正常关闭客户端代理(见下面的代码),服务器仍然记录“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>
客户端代码使用服务(VS2012使用“添加服务引用”为我生成客户端代理):
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.Close();
}
else
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
}
}
一切都运行得很好:
调用服务
关闭客户端
12
但是,应用程序终止后,服务器会记录异常。我知道我不应该担心这个异常,因为它按预期工作(异常仅出现在日志中),并且在调用 .Close()
/.Abort()
之前如果客户端突然终止也可能发生。
但是,这是正常的行为吗?我的意思是,如果我正确地关闭了客户端代理,我希望服务器不会记录异常(这会污染我的日志)。 我还假设,在关闭客户端代理后,客户端和服务器之间仍然建立了一些TCP连接(未知状态),因为服务器仅在整个客户端应用程序终止后记录异常。如果仍然存在这样的连接,是否会引入意外行为(例如最大连接客户数)?这是真的可以预料的吗?
我找到了不同的线程讨论此问题:
wcf "An existing connection was forcibly closed by the remote host" after closing client
结论是“不要在意它”。
有人可以提供一些参考资料来证实这一点,并解释为什么仍然会抛出此异常吗?
编辑:
异常的日志跟踪:
<Exception>
<ExceptionType>System.Net.Sockets.SocketException, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>An existing connection was forcibly closed by the remote host</Message>
<StackTrace>
à System.ServiceModel.Channels.SocketConnection.HandleReceiveAsyncCompleted()
à System.ServiceModel.Channels.SocketConnection.OnReceiveAsync(Object sender, SocketAsyncEventArgs eventArgs)
à System.Net.Sockets.SocketAsyncEventArgs.FinishOperationAsyncFailure(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
à System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
à System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
<ExceptionString>System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host</ExceptionString>
<NativeErrorCode>2746</NativeErrorCode>
</Exception>
非常感谢
EDIT 2:当我在IIS中托管服务或者在Windows服务中进行自主托管时,我遇到了同样的问题。
EDIT 3: 这里是一个完整的示例以重现该问题: http://speedy.sh/ENB59/wcf-test.zip
EDIT 4:
我试图监视WCF为我建立的TCP连接底层实际发生的情况。
在关闭客户端代理后,我仍然看到一个打开的TCP连接到我的服务器:
我认为这与TCP连接可能被缓存以便将来重新使用(即连接池)有关,因为向服务器打开一个新连接(在第一个客户端代理已关闭之后)不会创建新的TCP连接。如果我在应用程序中调用Console.WriteLine(new Test().TestTask().Result);
两次,则仍然只看到一个打开的TCP连接。
我还注意到,如果在关闭客户端通道后等待太久,此连接将因超时而死亡。
EDIT 5:好的,我在MSDN上找到了关于连接池的文档:
NetTcpBinding基于服务的主机DNS名称和服务侦听的端口号使用TCP连接池。当客户端对不同端口上的不同服务进行调用时,或者服务托管在单个进程中且共享一个端口时,这很有效。如果单个客户端调用在不同进程中托管的多个共享端口的服务,或者是WAS/IIS托管的服务,则客户端端的池化可能导致将Service A的连接重用于Service B,从而导致抛出异常,连接中止并创建新通道。要避免这个问题,请使用CustomBinding并为客户端与之通信的每个服务指定不同的ConnectionPoolSettings.GroupName。
那么现在我的问题是:如果这是正常行为,我该怎么做才能防止我的日志被所有这些异常所污染?
finally
块是否可能是问题的源头。我只是提出这个问题,因为在合理的审视下,我没有看到您代码中的问题,但是如果在try
块中发生了什么事情,您可能会尝试在一个不良或故障状态的通道上调用Close()
。尽管您在catch
块中将其设置为null
,但如果发生了一些有趣的事情,并且它不是捕获的异常呢? - Timproxy.Close();
,您正在告诉服务器强制关闭连接,因此从逻辑上讲,服务器记录了正确的异常,或者我在这里漏掉了什么吗? - Furqan Hameedi