首页 > 解决方案 > WCF 服务 - 客户端在多次请求本地主机后收到 CommunicationException

问题描述

我设置了一个基于 NetTcpBinding 的 WCF 服务,并且我使用的是 localhost。客户端和主机在同一台机器上运行。我在一段时间内使用 WCF 服务接口的特定方法的客户端出现通信异常。while 循环是强制性的,因为我正在监视一个值,而操作取决于值的变化。客户端是一个 clr 控制台应用程序,包含一个带有服务引用的 dll 和客户端的 app.config 文件。

为了尝试解决这个问题,我在绑定配置中增加了 openTimeout、closeTimeout、receiveTimeout、sendTimeout、maxBufferPoolSize 和 maxReceivedMessageSize,但没有任何成功。

我也让客户端的线程休眠,这样接口的方法调用的频率就少了,也没有任何成功。

为了给你一个想法,你可以在下面找到调用接口方法的客户端的while循环。我还附上了客户端的绑定配置。

While循环:

        while (ClientOfIPCService.getUGUDasDouble(ControlUGUD) == ValueOfControlUGUD)
        {
            Console::WriteLine("Request acProgState...");
            CurrentProgStat = ClientOfIPCService.getNCKVariableWithPathasDouble("/Channel/State/acProg[u1,1]");
            if (CurrentProgStat == 0 || CurrentProgStat == 3 || CurrentProgStat == 4)
            {
                exit(0);
            }
        }

我现在的问题是如何解决这个问题?有没有可能我清空请求的缓冲区?如何避免此通信异常?

2019 年 1 月 8 日更新:

Host的完整App.config文件:

  <system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MexGet">
                <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>              
        </serviceBehaviors>
    </behaviors>


<!--Binding Settings-->
<bindings>
  <netTcpBinding>
    <binding name="BindingConfig1"
             closeTimeout="00:30:00"
             openTimeout="00:30:00"
             receiveTimeout="00:30:00"
             sendTimeout="00:30:00"
             maxReceivedMessageSize="20000000"
             maxBufferSize="20000000"
             maxBufferPoolSize="20000000">
      <readerQuotas maxDepth="32"
                    maxStringContentLength="20000000"
                    maxArrayLength="20000000"
                    maxBytesPerRead="20000000"/>
    </binding>
  </netTcpBinding>
</bindings>


<!--Service Binding-->
<!--2. Configure end point with netTcpBinding-->
<services>
  <service behaviorConfiguration="MexGet"
      name="PROKOS_IPC_SERVER.HMI_IPC">
    <endpoint name="NetTcpBindingEndpoint" 
              address=""
              binding="netTcpBinding"
              bindingConfiguration="BindingConfig1"
              contract="PROKOS_IPC_SERVER.IHMI_IPC">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>

<!--3. Configure the meta data exchange end point-->
    <endpoint name="MexTcpBidingEndpoint"
              address="mex"
              binding="mexTcpBinding"
              bindingConfiguration=""
              contract="IMetadataExchange">
      <identity>
        <dns value="localhost" /> 
      </identity>
    </endpoint>
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:8124/HMI-IPC" />
      </baseAddresses>
    </host>
  </service>
</services>

客户端的完整 App.config 文件:

    <system.serviceModel>

  <!--Binding Settings-->
  <bindings>
    <netTcpBinding>
      <binding name="BindingConfig1" closeTimeout="00:30:00" openTimeout="00:30:00"
        receiveTimeout="00:30:00" sendTimeout="00:30:00" maxBufferPoolSize="20000000"
        maxReceivedMessageSize="20000000" />
    </netTcpBinding>
  </bindings>

    <client>
        <endpoint address="net.tcp://localhost:8124/HMI-IPC" binding="netTcpBinding"
            bindingConfiguration="BindingConfig1" contract="IPC.IHMI_IPC"
            name="NetTcpBindingEndpoint">
            <identity>
                <dns value="localhost" />
            </identity>
        </endpoint>
    </client>
</system.serviceModel>

在这里,我附上了服务器堆栈跟踪的屏幕截图:

服务器堆栈跟踪

客户端的完整错误消息是:“套接字连接已中止。这可能是由于处理您的消息时出错或远程主机超出接收超时,或底层网络资源问题造成的。本地套接字超时为'00 :29:59.9549975'。”

我没有在客户端处理异常,这在我的 clr 控制台应用程序中给出了以下错误消息。

客户端的错误信息

2019 年 2 月 8 日更新:

以下代码显示了让线程休眠以避免许多请求的想法:

        while (ClientOfIPCService.getUGUDasDouble(ControlUGUD) == ValueOfControlUGUD)
    {
        delay(500);
        Console::WriteLine("Request acProgState...");
        CurrentProgStat = ClientOfIPCService.getNCKVariableWithPathasDouble("/Channel/State/acProg[u1,1]");
        if (CurrentProgStat == 0 || CurrentProgStat == 3 || CurrentProgStat == 4)
        {
            exit(0);
        }

        // lets the current thread sleep for X miliseconds
        delay(500);
    }

另一个想法是集成一种方法,我可以在while循环之后切断电线并再次打开它以供进一步使用。

2019 年 2 月 8 日更新:

我根据需要启用了 WCF 跟踪,并且可以从跟踪中获取以下异常详细信息(请参阅屏幕截图和消息下方的翻译):

“套接字被中止,因为来自套接字的异步接收未在分配的时间限制 00:02:00 内完成。为此任务分配的时间段可能是较长超时的一部分。”

WCF服务的服务跟踪

标签: c#wcfclrnettcpbindingcommunicationexception

解决方案


错误详情是什么?
由于 Nettcpbinding 默认使用消息安全模式和 Windows 帐户作为客户端凭据,因此尽管服务器和客户端在同一台机器上,但我们应该在客户端提供 Windows 凭据。
此外,请在配置文件中发布完整的 System.servicemodel 部分。如果要修改配置,请优先修改服务器的绑定配置。
如果问题仍然存在,请随时告诉我。
更新
我建议您将 Nettcpbinding 的安全模式明确指定为NONE

<bindings>
  <netTcpBinding>
    <binding name="willbeappliedontheendpoint">
      <security mode="None"></security>
    </binding>
  </netTcpBinding>
</bindings>

同时删除不相关的配置。
然后我怀疑连接可能没有正常关闭,请在退出前尝试手动关闭循环内的通信连接。
另外,我们也可以尝试使用 ChannelFactory 来封装调用服务的函数。
https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.channelfactory-1?view=netframework-4.8
最后请参考下面的链接,希望对你有用。
套接字连接被中止 - CommunicationException


推荐阅读