WCF服务停止工作10054 WSAECONNRESET由对等方重置连接

时间:2015-11-18 15:30:03

标签: c# wcf

我的计算机(Windows 8)中的Windows窗体应用程序(C#/ .NET 4)中运行了两个WCF服务:

首次服务:https://localhost:9002

第二项服务:https://local_192-168-1-104.desktop.Company.com:9003

第一个服务在本地访问,第二个服务由本地网络中的其他计算机访问。主机:local_192-168-1-104.desktop.Company.com由DNS解析为ip:192.168.1.104,这是我的本地网络IP地址。

两种服务都使用https,第一种使用自签名证书,第二种使用证书:desktop.Company.com

问题:经过一段时间不活动后,第二个服务停止工作。

不记录任何异常,并且不执行WebServiceHost的事件Faulted(),UnknownMessageReceived(),Closing()或Closed()。

如果我关闭应用程序并再次启动,则问题仍然存在。在此错误情况下,WebServiceHost的State属性为" Opened",但服务不响应。

如果我停止服务,请重新配置服务(主题:配置证书服务2),然后再次启动,问题会停止一段时间。

我使用以下方法测试wcf服务:

using (WebClient webClient = new WebClient())
{
    webClient.DownloadDataCompleted += webClient_DownloadDataCompleted;
    webClient.DownloadDataAsync(new Uri("https://local_192-168-1-104.desktop.Company.com:9003/Message/Test"));
}

我收到了这个例外:

基础连接已关闭:发送时发生意外错误。

>> INNER EXCEPTION:
Message: An existing connection was forcibly closed by the remote host
Type: System.Net.Sockets.SocketException (System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
Source: System
TargetSite: Int32 EndReceive(System.IAsyncResult)
ErrorCode: 10054
StackTrace:
---------------------------
   at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
   at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
---------------------------

Windows错误代码 10054 是:

由同行重置连接。

  

远程主机强行关闭现有连接。这个   通常在远程主机上的对等应用程序结果时生成   突然停止,主机重启,主机或远程网络   接口被禁用,或远程主机使用硬关闭(请参阅   setsockopt有关远程SO_LINGER选项的更多信息   插座)。如果由于连接断开,也可能导致此错误   保持活动活动在一个或多个操作时检测到故障   正在进行中。正在进行的操作失败了   WSAENETRESET。后续操作因WSAECONNRESET而失败。

我尝试禁用Keep Alive,但问题仍然存在。

以下详细信息:

配置证书服务1

netsh http delete urlacl url=https://+:9002/
netsh http delete sslcert ipport=0.0.0.0:9002
netsh http add urlacl url=https://+:9002/ user=Everyone
makecert -sk RootCA -sky signature -pe -n CN=localhost -r -sr LocalMachine -ss Root certificate\CustomCertificate_MyCA.cer
makecert -sk server -sky exchange -pe -n CN=localhost -ir LocalMachine -is Root -ic certificate\CustomCertificate_MyCA.cer -sr LocalMachine -ss My certificate\CustomCertificate.cer
(install certificate in CertificateStore)
netsh http add sslcert ipport=0.0.0.0:9002 certhash=F3F40BF81AF0.... appid={00a1d32c-68bd-4693-a872-...}

启动服务1

var mainServiceHost = new Company.Library.WCF.JSONServiceHost("localhost", 9002, true);
mainServiceHost.Start(typeof(Service.Message), typeof(Service.IMessage), false);

配置证书服务2

netsh http delete urlacl url=https://+:9002/
netsh http delete sslcert ipport=192.168.1.146:9003
netsh http add urlacl url=https://+:9003/ user=Everyone
(install certificate in CertificateStore)
netsh http add sslcert ipport=192.168.1.146:9003 certhash=1C36C9C... appid={00a1d32c-68bd-4693-a872-1473...}

启动服务2

var localServerServiceHost = new Company.Library.WCF.JSONServiceHost("local_192-168-1-104.desktop.Company.com", 9003, true);
localServerServiceHost.Start(typeof(Service.Message), typeof(Service.IMessage), false);

JSONServiceHost类

public void Start(Type serviceType, Type implementedContract, bool keepAliveEnabled)
{
    EndpointAddress endpoint = new EndpointAddress(Url);

    CustomServiceBehavior serviceBehavior = new CustomServiceBehavior();
    svcWebHost.Description.Behaviors.Add(serviceBehavior);

    BindingElementCollection bindingElements;

    WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

    bindingElements = binding.CreateBindingElements();
    if (bindingElements != null)
    {
        var transport = bindingElements.Find<HttpsTransportBindingElement>();
        if (transport != null)
            transport.KeepAliveEnabled = keepAliveEnabled;
    }

    binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
    binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
    binding.ReaderQuotas.MaxDepth = int.MaxValue;
    binding.ReaderQuotas.MaxNameTableCharCount = int.MaxValue;
    binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
    binding.MaxBufferSize = int.MaxValue;
    binding.MaxBufferPoolSize = int.MaxValue;
    binding.MaxReceivedMessageSize = int.MaxValue;

    binding.SendTimeout = TimeSpan.FromMinutes(5);
    binding.ReceiveTimeout = TimeSpan.FromMinutes(5);
    binding.OpenTimeout = TimeSpan.FromMinutes(5);
    binding.CloseTimeout = TimeSpan.FromMinutes(5);

    ServiceEndpoint serviceEndpoint = svcWebHost.AddServiceEndpoint(implementedContract, binding, endpoint.Uri);

    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
    smb.HttpGetEnabled = true;
    svcWebHost.Description.Behaviors.Add(smb);

    ServiceDebugBehavior sdb = svcWebHost.Description.Behaviors.Find<ServiceDebugBehavior>();
    if (sdb != null)
        sdb.IncludeExceptionDetailInFaults = true;

    foreach (var operation in serviceEndpoint.Contract.Operations)
        operation.Behaviors.Add(new CustomOperationBehavior());

    svcWebHost.Open();
}

应用程序启动时执行的条件配置

private static void ConfigureGlobalServiceParameters()
{
    System.Net.ServicePointManager.CheckCertificateRevocationList = false;
    System.Net.ServicePointManager.DefaultConnectionLimit = int.MaxValue;
    System.Net.ServicePointManager.DnsRefreshTimeout = -1;
    System.Net.ServicePointManager.Expect100Continue = false;
    System.Net.ServicePointManager.MaxServicePointIdleTime = 20 * 1000;
    System.Net.ServicePointManager.MaxServicePoints = 10;
    System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(delegate { return true; });
    System.Net.ServicePointManager.UseNagleAlgorithm = false;
    System.Net.ServicePointManager.SetTcpKeepAlive(false, 0, 0);
}

CustomEndpointBehavior

public class CustomEndpointBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
        var customInspector = new CustomDispatchMessageInspector();
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(customInspector);
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

CustomOperationBehavior

public class CustomOperationBehavior : IOperationBehavior
{
    public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
    {   
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
    {
    }

    public void Validate(OperationDescription operationDescription)
    {
    }
}

CustomServiceBehavior

public class CustomServiceBehavior : IServiceBehavior
{
    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        CustomEndpointBehavior endpointBehavior = new CustomEndpointBehavior();
        foreach (var endpoint in serviceDescription.Endpoints)
            endpoint.Behaviors.Add(endpointBehavior);
    }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
    }
}

谢谢!

1 个答案:

答案 0 :(得分:1)

我回到这个问题,最后找到了解决方案。

这不是WCF的问题,WCF停止工作,因为证书与Windows端口的关联不起作用。

问题:

  1. 您有证书(不是自签名证书);
  2. 您使用以下命令将此证书关联到Windows端口:“netsh http add sslcert”并在WCF或其他服务中使用它;
  3. 重新启动或系统闲置很长时间后,此操作停止;
  4. <强>后果:

    在Windows重新启动后,服务停止在此端口中工作,并且会出现以下描述的行为:

    1. 如果您尝试对url执行Http请求,则会收到以下错误: 基础连接已关闭:发送时发生意外错误。

    2. 如果您尝试再次将证书关联到端口,请使用以下命令:

    3. 命令:netsh http add sslcert ipport=192.168.1.146:9003 certhash=1C36.. appid={00a1..}

      您收到此错误:

        

      SSL证书添加失败,错误:1312   指定的登录会话不存在。它可能已经被终止。

      1. 如果您尝试导出证书,请使用以下:
      2. 命令:certutil -exportPFX -p "[password]" My [cert_SerialNumber] "c:\temp\desktop.pfx" NoChain

        您收到此错误:

          

        私钥不可导出   加密测试通过   CertUtil:-exportPFX命令FAILED:0x8009000b(-2146893813 NTE_BAD_KEY_STATE)   CertUtil:密钥无法在指定状态下使用。

        如何重现所有配置过程:

        1. 从.pfx获取证书:
        2. 代码:X509Certificate2 certificate = new X509Certificate2(certPath, password);

          1. 将证书证书添加到CertificateStore(StoreName:“MY”,StoreLocation:LocalMachine):

            X509Store store = new X509Store(storeName.My,StoreLocation.LocalMachine); store.Open(OpenFlags.ReadWrite); store.Add(证书); store.Close();

          2. 将证书附加到端口:

          3. 命令:netsh http add sslcert ipport=192.168.1.146:9003 certhash=1C36C... appid={00a..} clientcertnegotiation=enable

            1. 配置Windows防火墙以允许访问端口:
            2. (我这样做,因为我正在从本地网络中的另一台计算机访问WCF)

              如何手动解决问题:

              在本文中: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx

              有这个解决方案:

                

              我认为将自签名证书从“个人”转移到“受信任的根”   CA目录导致SSL在开发人员之后停止工作的问题   重启他们的机器。 (不知道它是如何发生的,但它确实发生了   始终如一。)我终于通过导出和重新导入解决了这个问题   将自签名证书放入受信任的根目录(而不是   只需拖动它)。现在我的自签名证书被认为是我   每次重新启动时都不需要重新安装/修复IIS Express   机。

              奇迹般地,您无需从个人证书存储区导出证书,并以Root身份导入证书。您只需要在Windows重新启动之前手动导出证书,并且在Windows重新启动后不会发生此问题。

              如何使用命令行解决问题:

              在配置过程之后,在第一次Windows重启之前,执行以下命令:

              1. 将证书导入“个人”证书存储:
              2. 命令:certutil -f -p "[password]" -importpfx My "c:\temp\cert.pfx"

                1. 使用以下方法导出证书:
                2. 命令:certutil -exportPFX -p "[password]" My [certificate_Serial_Number] "c:\temp\cert2.pfx" NoChain

                  有价值的信息:

                  1. 列出Windows Local Machine Certification Store中安装的证书:

                    • 开始/运行:mmc.exe
                    • 文件/添加/删除管理单元...
                    • 在“可用的管理单元”下,选择“证书”,然后选择“本地计算机”,然后按添加。
                  2. 使用命令“netsh http add sslcert”列出与端口关联的证书

                  3. 命令:certutil -store "My"

                    1. 删除证书与端口的关联:
                    2. 命令:netsh http delete sslcert ipport=192.168.1.104:9003

                      1. certutil reference:
                      2. https://technet.microsoft.com/en-us/library/cc732443.aspx

                        1. netsh参考:
                        2. https://msdn.microsoft.com/en-us/library/windows/desktop/cc307220(v=vs.85).aspx