2011-12-29 4 views
2

WCF net.tcp 통신을 테스트하는 샘플 서비스가 있습니다. 매우 간단한 서비스이며 클라이언트가 서비스에 가입 한 후 callbackchannel을 호출하여 연결된 모든 클라이언트에게 브로드 캐스트 메시지를 알립니다. 이 서비스는 IIS 7.5에서 호스팅됩니다.WCF 이중 TCP 통신 오류

테스트 코드는 서비스 코드 및 테스트 클라이언트입니다.

[ServiceBehavior(Name = "CuratioCSMService", InstanceContextMode = InstanceContextMode.PerSession)] 
public class Service1 : ISampleCuratioService 
{ 
    private static List<ISampleServiceCallBack> JoinedClien = new List<ISampleServiceCallBack>(); 

    public void SubcribeToService(string sub) 
    { 
     var subscriber = OperationContext.Current.GetCallbackChannel<ISampleServiceCallBack>(); 
     if (!JoinedClien.Contains(subscriber)) 
     { 
      JoinedClien.Add(subscriber); 
     } 
    } 

    public string GetData(int value) 
    { 
     return string.Format("You entered: {0}", value); 
    } 

    public void Broadcast(string message) 
    { 
     JoinedClien.ForEach(c => c.NotifyClient("message was received " + message)); 
    } 
} 

내가 그것을 실행할 때 내가 할 행동을 이해할 수 없다 : 여기

[ServiceContract(CallbackContract = typeof(ISampleServiceCallBack), SessionMode = SessionMode.Required)] 
public interface ISampleCuratioService 
{ 
    [OperationContract(IsOneWay = true)] 
    void SubcribeToService(string sub); 

    [OperationContract] 
    string GetData(int value); 

    [OperationContract(IsOneWay = true)] 
    void Broadcast(string message); 
} 

public interface ISampleServiceCallBack 
{ 
    [OperationContract(IsOneWay = true)] 
    void NotifyClient(string message); 
} 

는 서비스의 구현입니다. 첫 번째 클라이언트를 실행 한 후에도 문제가 없지만 테스트 클라이언트 응용 프로그램을 닫고 열 때 오류 상태 인 것처럼 채널을 통신에 사용할 수 없음을 알리는 예외가 발생합니다. 나는 5 클라이언트를 실행하면

static void Main(string[] args) 
    { 
     var callneckclient = new ServiceClientProxy(); 
     var client = new SampleCuratioServiceClient(new InstanceContext(callneckclient)); 
     client.SubcribeToService("me"); 
     Console.ReadLine(); 

     for (int i = 0; i < 15; i++) 
     { 
      Console.WriteLine(client.GetData(5)); 
      client.Broadcast("this is from client me"); 
     } 
     client.Close(); 
     Console.Read(); 
    } 

    public class ServiceClientProxy : ISampleCuratioServiceCallback, IDisposable 
    { 
     public void NotifyClient(string message) 
     { 
      Console.WriteLine(message); 
     } 

     public void Dispose() 
     { 
      GC.SuppressFinalize(this); 
     } 
    } 

상황도 버그를 가져옵니다

이 샘플 테스트 클라이언트입니다. 메시지를 보내거나받지 않습니다.

답변

3

클라이언트가 SubcribeToService을 호출하면 JoinedClien이라는 목록에 작업 컨텍스트를 추가합니다.

서버에 Broadcast을 호출하면 연결된 모든 클라이언트에 대해 수집 된 모든 작업 컨텍스트에서 NotifyClient 메서드를 호출합니다.

연결이 끊긴 클라이언트가 JoinedClien 목록에서 제거되지 않는 것이 문제입니다. 연결이 끊긴 작업 컨텍스트에서 작업 메서드를 호출하려고하면 채널이 오류 상태 인 오류가 발생합니다. 신규 고객을 추가 할 때

public void Broadcast(string message) 
{ 
    // copy list of clients 
    List<OperationContext> clientsCopy = new List<OperationContext>(); 
    lock(JoinedClien) { 
     clientsCopy.AddRange(JoinedClien); 
    } 

    // send message and collect faulted clients in separate list 
    List<OperationContext> clientsToRemove = new List<OperationContext>(); 
    foreach (var c in JoinedClien) 
    { 
     try { 
      c.NotifyClient("message was received " + message)); 
     } 
     catch (CommunicationException ex) { 
      clientsToRemove.Add(c); 
     } 
    } 

    foreach (var c in clientsToRemove) 
    { 
     lock(JoinedClien) { 
      if(JoinedClien.Contains(c)) 
       JoinedClien.Remove(c); 
     } 
    } 
} 

:

당신이 Channel_ClosedChannel_Faulted 이벤트를 구독하고 또한 오류가 발생한 클라이언트의 동작 상황을 다시 클라이언트로 호출 할 때 CommunicationException를 잡아 제거해야 해결하려면 해당 작업을 잠금 처리해야합니다.

var subscriber = OperationContext.Current.GetCallbackChannel<ISampleServiceCallBack>(); 
lock(JoinedClien) 
{ 
    if (!JoinedClien.Contains(subscriber)) 
    { 
     JoinedClien.Add(subscriber); 
    } 
} 
+0

잠금에 대한 추가 정보를 제공해주십시오. 내 말은 내가 당신의 충고에 따라 서비스를 수정했다는 것입니다. 오류 상태에 대한 체크 코드가 포함되어 있습니다. –

+0

공유 데이터 – Jan

+0

과 마지막 질문의 동기화 된 액세스를 보여주기 위해 제 대답을 업데이트 했습니까? 이 알림 및 푸시 기반 서비스를 구현 한 방식에 관한 제안이나 의견을 제시 할 수 있습니까? 이것이 클라이언트 목록을 유지하고 알림을 보내는 올바른 방법입니까? TCP 바인딩이 세션과 함께 사용 되는가? –