5

我有一个使用 netTcpBinding 和回调方法的主机/客户端 WCF 服务和客户端。

<bindings>
      <netTcpBinding>
        <binding name="tcp_Unsecured" receiveTimeout="00:01:00" sendTimeout="00:01:00">
          <security mode="None" />
          <reliableSession enabled="true" ordered="true" inactivityTimeout="00:10:00"/>
        </binding>
      </netTcpBinding>
</bindings>

代理人

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples", ConfigurationName="AlarmServer", CallbackContract=typeof(AlarmServerCallback), SessionMode=System.ServiceModel.SessionMode.Required)]
public interface AlarmServer
{

    [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/RegisterAlarm")]
    void RegisterAlarm(System.DateTime alarmTime, string clientName, string reminderMessage);

    [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/unRegisterAlarm")]
    void unRegisterAlarm(string clientName);

    [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/broadcastMessage")]
    void broadcastMessage(string msg);
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface AlarmServerCallback
{

    [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/SignalAlarm")]
    void SignalAlarm(string reminderMessage);

    [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/displayMessage")]
    void displayMessage(string msg);
}

带有回调的客户端实例

public MainForm()
{
    InitializeComponent();
    InstanceContext context = new InstanceContext(new AlarmCallback());
    client = new AlarmServerClient(context);
}

我遇到的问题是绑定recieveTimeout 触发后,客户端进入故障状态并关闭客户端监听回调。

我可以使用来自 sysinternals 的 TCPVIEW 看到侦听端口下降。

如果我让通道保持忙碌,则不会触发超时,因此它不是发送给服务器/客户端的 WCF 消息中的故障,因为多条消息将正常流过。

我认为 receiveTimeout 旨在提供一种方法来检测 WCF 消息通过 TCP 的回复是否失败?为什么会出现连接错误。几乎可以看出,如果超时期间没有创建回调对象,那么通道就关闭了?

我究竟做错了什么?

4

3 回答 3

6

似乎接收超时会导致回调主机服务在达到其最大计数后出现故障。这是 23.59 小时或默认值 1 分钟。我可以通过将 receivetimeout 设置为 Infinate 来解决超时问题

 <bindings>
      <netTcpBinding>
        <binding name="NetTcpBinding_AlarmServer" receiveTimeout="infinite" >
          <security mode="None" />        
        </binding>
      </netTcpBinding>
    </bindings>

但这让我现在想知道我是否真的在 WFC 中使用正确的工具进行服务器/客户端通信。我希望主机/服务器在文件服务器上运行,并且多个远程客户端连接到它。客户端会用心跳 ping 服务器,偶尔服务器可能会向客户端发送命令。我正在使用远程处理或 tcpsockets 并使用“客户端轮询方法”来执行此操作,其中命令在数据库中排队,当客户端每 10 分钟轮询一次服务器以获取命令时,如果该唯一客户端有一个挂起的命令它得到它。这工作正常,并且具有与服务器没有 1000 个打开的 tcp 套接字连接的优点,因为客户端只会随机连接和断开连接。

帮助我错过了这里的概念???

于 2010-05-13T23:05:55.820 回答
4

当没有接收到应用程序消息时,设置 receiveTimeout 的值将告诉服务在通信通道故障之前等待多长时间。您始终可以将此超时值增加到更大的数字(默认为 10 分钟),但您还必须增加会话不活动超时。有关这两种超时的更多信息,请参阅http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.binding.receivetimeout.aspx 。

当接收或不活动超时触发时,双工通道出现故障。您必须在客户端创建一个新代理才能再次与服务器通信。

在尝试调用服务器之前,您始终可以在客户端检查通道连接状态。如果通道的 CommunicationState 没有打开,那么可以在调用服务器之前创建一个新的代理。

于 2010-07-28T21:23:19.217 回答
3

您是否尝试过在代理创建(客户端)中使用DuplexChannelFactory ?以下是它的使用方法(使用new AlarmServerClient(context)替换创建):

AlarmServer proxy = new DuplexChannelFactory<AlarmServer>(context,"YourAlarmServerEndpoint").CreateChannel();

编辑:启用日志分析跟踪:

通过启用消息记录和跟踪,可以分析通道通信:

<system.diagnostics>
<sources>
  <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
    <listeners>
      <add type="System.Diagnostics.DefaultTraceListener" name="Default">
        <filter type="" />
      </add>
      <add name="ServiceModelMessageLoggingListener">
        <filter type="" />
      </add>
    </listeners>
  </source>
  <source name="System.ServiceModel" switchValue="Information,ActivityTracing"
    propagateActivity="true">
    <listeners>
      <add type="System.Diagnostics.DefaultTraceListener" name="Default">
        <filter type="" />
      </add>
      <add name="ServiceModelTraceListener">
        <filter type="" />
      </add>
    </listeners>
  </source>
</sources>
<sharedListeners>
  <add initializeData="Your_svclog_file_here"
    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
    <filter type="" />
  </add>
  <add initializeData="Your_svclog_file_here"
    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
    <filter type="" />
  </add>
</sharedListeners>
<trace autoflush="true" />

在这种情况下,Trace 能够记录“信息”。看到渠道创建很重要。

要分析 svclog 文件,可以使用 Service Trace Viewer - Microsoft Windows SDK,通常在 C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe

于 2010-05-12T16:15:12.460 回答