【问题标题】:WCF Service - Client receiving CommunicationException after many requests to localhostWCF 服务 - 客户端在多次请求本地主机后收到 CommunicationException
【发布时间】:2019-07-31 14:00:27
【问题描述】:

我设置了一个基于 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>

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

Server stack trace

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

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

Error message of client

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 时间限制内完成,因此套接字被中止。为此任务分配的时间段可能是较长超时的一部分。”

Service Trace of the WCF service

【问题讨论】:

  • 调用堆栈是什么样的以及完整的异常是什么(因此包括任何内部异常)。请随时edit
  • 我希望通过屏幕截图为您提供所需的信息。
  • 当该异常发生时(看起来像套接字错误),您能否从命令提示符netstat -a -p tcp 运行并告诉我们TIME_WAIT 中有多少端口?您可能想尝试降低 TcpTimedWaitDelay:docs.microsoft.com/en-us/biztalk/technical-guides/… 如果有很多(阅读数百或更多)
  • 在服务器端使用完整的消息日志配置 WCF 跟踪:docs.microsoft.com/en-us/dotnet/framework/wcf/diagnostics/…
  • 请参考我更新的问题。很抱歉回复晚了,但我花了一些时间来实现它。

标签: c# wcf clr nettcpbinding communicationexception


【解决方案1】:

错误详情是什么?
由于 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
最后请参考下面的链接,希望对你有用。
The socket connection was aborted - CommunicationException

【讨论】:

  • 我贴出了主机和客户端的整个配置文件。不幸的是,问题仍然存在。
  • 完整的错误信息是什么?您的客户端似乎不是基于 C#。您介意分享有关您的客户端的更多详细信息吗?我们可以使用 ChannelFactory 调用服务吗?当我们使用 while(true) 循环时会报错吗?
  • 我的客户端是一个 clr 控制台应用程序,它使用 dll 使用服务。此 .dll 包括服务参考和客户端的 app.config。这样的设计是强制性的,因为我有一些用 C++ 编写的源文件,我需要进行一些计算。为了将 C++ 源文件和 WCF 服务结合在一起,我创建了一个 CLR 控制台应用程序,它允许我使用该服务并使用 C++ 源文件。我上传了完整的错误消息。退出while循环后直接报错,尝试再次使用wcf-service的相同方法。
  • 您的更新很好地描述了我的问题。如果我的客户只运行了大约 30 分钟,我的服务就可以正常工作。如果它运行了 2h 或更长时间,这意味着 while 循环发出了很多请求,就会出现异常。我的想法是在 while 循环离开时关闭通道,然后再打开它。但我该怎么做呢?另一个想法是让线程在while循环中休眠以减少请求。这有什么好处吗?我的想法显示在我的问题更新中。
  • 你的想法很棒。希望这能解决问题。通过使用通道工厂或客户端代理类访问服务,我们都需要一个客户端对象,该对象具有打开和关闭通道(连接)的方法。
【解决方案2】:

我设法解决了这个问题。以下是我的问题和解决方案的简短总结。

问题总结: 我创建了一个配置为 nettcpbinding 的 WCF 服务。我有一个包含 dll 并构建为 clr 控制台应用程序的客户端(dll 包含客户端的 app.config 和使用添加服务引用创建的客户端代理)。客户端有一个带有 while 循环的函数,通过服务请求一个值。由于客户端运行时间较长,我的服务会引发通信异常。

问题的解决方案: 我使用 svcUtil.exe 创建了一个新代理,其中包含关闭和打开通道的方法。因此,在我的函数中,我创建了一个客户端类的新实例,并在函数的开头和结尾打开和关闭了通道。此外,我让线程在 while 循环中休眠,以免向服务发出太多请求。

在 main 函数之后,我还为进一步的请求创建了一个新实例。这解决了我的问题。我的客户端中的函数代码如下所示:

while (myClient.getUGUDasDouble(ControlUGUD) == ValueOfControlUGUD)
    {

        delay(500);
        //Console::WriteLine("Request acProgState...");
        CurrentProgStat = myClient.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);

    }


    if (myClient.getUGUDasDouble(ControlUGUD) == 2)
    {
        myClient.setUGUDasDouble(ControlUGUD, -1);
    }
    else
    {
        MessageBox(0, (LPCWSTR)L"Error :::: IPC Communication Control: Function WaitTillNCFinishedTheJob() :::: Failure: NC needed to write MTU_G_C_NC = 2!", (LPCWSTR)L"Error", MB_ICONWARNING | MB_OK);
        exit(0);
    }

    myClient.Close();
    Console::WriteLine("Communication state: " + myClient.State.ToString());

由于我是 WCF 新手,这种方法对我有用并解决了我的问题。此问题的回调事件可能是更好的方法(请参阅链接)。

Callback events via WCF

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    相关资源
    最近更新 更多