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

예외 메시지를 읽었습니까? –

+0

예, 읽었지만 이해할 수 없습니다 ... Mayby ... 저는 지금 영어로하지 않습니다; ( – user1031034

답변

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를 업데이트하기 위해 디스패치해야하는 스레드 풀 스레드에 UI가 삽입됩니다.

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

당신이 들면, ConcurrencyMode를 이해하려면 그것은 당신이 정말로 그것을 조금 복잡처럼 읽는 someback 땅을 수행해야합니다 다음 실행에 어떻게 영향을 미치는지 경우 - 그러나 당신이 그 배경이 없다면 정말 이해하기 어렵다 ConcurrencyMode를 변경할 때 어떤 일이 발생합니다. 이 dasBlonde blog post입니다. 다른 모드와 동작은입니다.하지만 좀 더 초보자 인 자습서로 시작하고 싶을 수도 있습니다.

+0

또한 서비스에서 UseSynchronizationContext는 false 여야합니다 –

관련 문제