2012-04-21 192 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