2012-04-21 193 views
0

在我的客户端/服务器应用程序中,我希望在所有人客户端中计数其他值。 我用回调做了应用程序,但有些地方是错误的。我得到异常,当我想要调用方法pipeproxy.polacz(S);现在,它获得服务器的价值,并在服务器控制台中写入。WCF服务器/客户端回调,从客户端到服务器的回复

的例外是:

This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on CallbackBehaviorAttribute.

另一个问题是,在和所有的客户这个funkction如何resault。 例子;

client 1: S = 1; 
client 2: S = 2; 
client 3: S = 3; 

而且这个函数从所有的客户端取得结果并对其进行求和。所以服务器将在服务器控制台中写入6。

我的应用程序代码:

服务器:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ServiceModel; 
using Interface; 

namespace WCFapp 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Klienci cust = new Klienci(); 
      cust.Connect(); 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Interface; 

namespace WCFapp 
{ 
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 
class Klienci : IMessage 
{ 
    private static List<ImessageCallback> subscribers = 
     new List<ImessageCallback>(); 

    public void lista() 
    { 
     string nm = Console.ReadLine(); 
     if (nm == "1") 
     { 
      Console.WriteLine("Number of conected clients: " + subscribers.Count()); 
      funkcja(); 

     } 
    } 

    public void Connect() 
    { 
     using (ServiceHost host = new ServiceHost(
      typeof(Klienci), new Uri("net.tcp://localhost:8000"))) 
     { 
      host.AddServiceEndpoint(typeof(IMessage), 
       new NetTcpBinding(), "ISubscribe"); 

      try 
      { 
       host.Open(); 
       lista(); 
       Console.ReadLine(); 
       host.Close(); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 
     } 
    } 

    public bool Subscribe() 
    { 
     try 
     { 
      ImessageCallback callback = OperationContext.Current.GetCallbackChannel<ImessageCallback>(); 
      if (!subscribers.Contains(callback)) 
       subscribers.Add(callback); 
      Console.WriteLine("Client is conected ({0}).", callback.GetHashCode()); 
      return true; 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
      return false; 
     } 
    } 

    public bool Unsubscribe() 
    { 
     try 
     { 
      ImessageCallback callback = OperationContext.Current.GetCallbackChannel<ImessageCallback>(); 
      if (subscribers.Contains(callback)) 
       subscribers.Remove(callback); 
      Console.WriteLine("Client is unconected ({0}).", callback.GetHashCode()); 
      return true; 
     } 
     catch 
     { 
      return false; 
     } 
    } 

    public void funkcja() 
    { 
     int a = 1; int b = 3; 
     subscribers.ForEach(delegate(ImessageCallback callback) 
     { 
      if (((ICommunicationObject)callback).State == CommunicationState.Opened) 
      { 
      Console.WriteLine("a= {0} , b= {1}", a, b); 
      callback.klient_licz(a, b); 
      a++; 
      b++; 
      } 
     }); 

    } 

    public void polacz(int S) 
    { 

     Console.WriteLine("Sum: {0}", S); 
    } 
    } 
} 

接口:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ServiceModel; 


namespace Interface 
{ 
    [ServiceContract(CallbackContract = typeof(ImessageCallback), SessionMode = SessionMode.Required)] 
public interface IMessage 
{ 
    [OperationContract] 
    void funkcja(); 

    [OperationContract] 
    void polacz(int S); 

    [OperationContract] 
    bool Subscribe(); 

    [OperationContract] 
    bool Unsubscribe(); 

} 
[ServiceContract] 
public interface ImessageCallback 
{ 
    [OperationContract] 
    void klient_licz(int a, int b); 
} 

}

客户:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ServiceModel; 
using Interface; 

namespace Client 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      clients cl = new clients(); 
      if (cl.Conect() == true) 
      { 
       string tmp = Console.ReadLine(); 
       while (tmp != "EXIT") 
       { 
        cl.SendMessage(tmp); 
        tmp = Console.ReadLine(); 
       } 

      } 
      cl.Close(); 
      Environment.Exit(0); 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ServiceModel; 
using Interface; 

namespace Client 
{ 
    class clients : ImessageCallback, IDisposable 
    { 
     IMessage pipeProxy = null; 
     public bool Conect() 
     { 
      DuplexChannelFactory<IMessage> pipeFactory = 
       new DuplexChannelFactory<IMessage>(
        new InstanceContext(this), 
        new NetTcpBinding(), 
        new EndpointAddress("net.tcp://localhost:8000/ISubscribe")); 
      try 
      { 
       pipeProxy = pipeFactory.CreateChannel(); 
       pipeProxy.Subscribe(); 
       return true; 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
       return false; 
      } 

     } 

     public void Close() 
     { 
      pipeProxy.Unsubscribe(); 
     } 


     public void klient_licz(int a, int b) 
     { 
      int S = a + b; 
      Console.WriteLine("Sum= {0}", S); 
      pipeProxy.polacz(S); //ERROR 
     } 

    } 
} 
+0

您是否读过异常消息? – 2012-04-21 18:43:11

+0

是的,我读过了,但我不明白这一点... Mayby ...我现在没有多少英文;( – user1031034 2012-04-21 19:58:21

回答

1

这里的问题是,在您的回调方法klient_licz(由服务器调用)中,您正在进行另一个服务器调用。这是不允许的,因为你的合同目前正在建立。

  1. 检查你是否真的需要这种行为。你是否真的需要在回调接口(klient_licz)上的一个方法内进行服务器调用。

  2. 如果您确实需要这种行为,那么您可以通过在回调接口上标记klient_licz调用OneWay来解决问题。这将意味着服务器对回调的调用不会阻塞,直到客户端返回(这是当前导致问题的原因,因为服务器正在等待客户端调用返回,但客户端调用正在等待服务器的调用):

    [ServiceContract] 
    public interface ImessageCallback { 
         [OperationContract(IsOneWay = true)] 
         void klient_licz(int a, int b); 
    } 
    
  3. 另外,您可以用标记比默认模式单以外的concurrancy模式回调执行力度。例如Reentrant,如下所示 - 但请记住,这意味着对回调的调用不会长时间集中到UI上,即,它将位于线程池线程上,因此您必须调度以从回调接口上的方法更新UI:

    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)] 
    class clients : ImessageCallback, IDisposable { 
    ... 
    } 
    

如果您想了解ConcurrencyMode以及它如何影响执行,那么你将真正需要做的someback地阅读,因为它确实变得有点复杂 - 但如果你没有这样的背景下,很难真正理解当您更改并发模式时会发生什么情况。这dasBlonde blog post有一个很好的摘要的不同模式和行为 - 但你可能想要开始一些教程,这是一个更多的初学者为导向。

+0

另外,在服务上,UseSynchronizationContext必须是false – 2013-04-23 08:44:08