WCF 服务 - 客户端在对本地主机发出多次请求后收到 CommunicationException

WCF Service - Client receiving CommunicationException after many requests to localhost

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

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

我也让client的线程休眠,这样接口的方法就少调用了,但是也没有成功。

为了给你一个思路,你可以在下面找到调用接口方法的客户端的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 日更新:

主机的完整 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

客户端完整报错信息为: "The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '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 跟踪,我可以从跟踪中获取以下异常详细信息(请参阅消息的屏幕截图和下面的翻译):

"The socket was aborted because an asynchronous receive from the socket was not completed within the assigned time limit of 00:02:00. The time period allocated for this task may have been part of a longer timeout."

Service Trace of the WCF service

错误详情是什么?
由于Nettcpbinding默认使用消息安全模式和Windows账户作为客户端凭证,所以我们应该在客户端提供windows凭证,尽管服务器和客户端在同一台机器上。
此外,请 post 配置文件中完整的 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
最后请参考下面的link,希望对你有用
The socket connection was aborted - CommunicationException

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

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

问题解决: 我使用 svcUtil.exe 创建了一个新代理,其中包含关闭和打开通道的方法。所以在我的函数中,我创建了一个新的客户端实例 class 并在函数的开头和结尾打开和关闭通道。此外,我让线程在 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 的新手,所以这种方法对我有用并且解决了我的问题。此问题的回调事件可能是更好的方法(参见 link)。

Callback events via WCF