2

我正在设计一个客户端-服务器聊天应用程序(实际上我不是,但让我们假装我是:)),我对我所经历的一些竞争条件感到有些困惑。

假设我有以下代码:

public interface IServer
{
  [OperationContract(IsOneWay = false)]
  [FaultContract(typeof(ChatException))]
  void BroadcastMessage(string msg);
}

public class Server : IServer 
{
  void BroadcastMessage(string msg) // I'm not mentionning the try/catch/throw FaultException here for readability purposes
  {
    foreach (IClientCallback c in callbacks){
      c.ReceiveMessage(msg);
    }

  }
}

public interface IClientCallback
{
  [OperationContract(IsOneWay = true)]
  void ReceiveMessage(string s);
}

这是绑定配置的摘录:

<endpoint address="" 
binding="netTcpBinding" 
bindingConfiguration="DuplexBinding" 
contract="IServer" />

 <binding name="DuplexBinding" sendTimeout="00:01:00">
   <reliableSession ordered="true" inactivityTimeout="00:05:00" enabled="true"/>
   <security mode="None">
     <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
     <message clientCredentialType="Windows" />
   </security>
 </binding>

这当然是某种伪 c#,为了清楚起见,我删除了很多不相关的代码。

现在切入正题:此代码不起作用。当我调用 BroadcastMessage 时,该方法永远不会返回,并且我最终在客户端出现超时。如果我在服务器端进行调试,一切似乎都很好(我完全按照预期从 BroadcastMessage 方法返回,并且我不会阻止任何 ReceiveMessage 单向调用)

以下是修复此代码的两种方法:

  1. 删除 FaultContract 并将 BroadcastMessage 方法声明为 oneway=true
  2. 向所有人广播消息,但最初的发件人

我的第一个猜测是客户端正在等待服务器返回,因此无法处理来自服务器的传入 ReceiveMessage 调用,从而阻塞服务器,但 ReceiveMessage 被声明为单向,并且调试服务器表明它不会阻止对 ReceiveMessage 的任何调用

现在,我的问题:

  • 这是怎么回事?

  • 还有其他方法可以解决这个问题吗?(也许通过调整绑定配置?)

  • 假设我选择了修复 2(即不向发送者广播),如果服务器在我等待自己的 BroadcastMessage 调用完成时调用我的 ReceiveMessage 回调(因为其他人向我发送了消息)会发生什么?

  • 我读过 OneWay 调用并不完全是单向的,服务器仍在等待来自另一端的 HTTP 响应。有这方面的详细信息吗?具体来说,当远程呼叫被阻止时,客户端是否能够响应此类 http 响应?

编辑:服务器端的控制台 .net 3.5,客户端的 Winforms .net 3.5

4

2 回答 2

2

这听起来像一个死锁,可能是由于同步上下文。什么是客户?温窗体?WPF?WCF 尊重同步上下文,这意味着 winform 和 WPF 的“切换到 UI 线程”。如果您在 UI 线程上发出阻塞请求,那么游戏结束。

尝试在后台线程上执行 WCF 请求,以便 UI 线程可用于处理传入请求;这可以像使用一样简单ThreadPool,或者也许BackgroundWorker

于 2009-01-23T09:32:29.617 回答
1

尝试将此属性添加到您的服务的具体实现中:

[System.ServiceModel.ServiceBehavior(UseSynchronizationContext=false)]
public class Server : IServer {}

其次,尝试打开 WCF 跟踪,看看你的 WCF 实现的内部是否发生了让你伤心的事情。我遇到了一些非常奇怪的错误,这些错误只有在我进行跟踪并发现正在发生的实际错误消息时才有意义。

跟踪 WCF 服务

于 2009-01-23T10:07:36.753 回答