2012-10-18 2 views
8

1. .net 클라이언트에서 클라이언트가 서버에 연결되어 있는지 (예 : 보내고받을 수 있는지) 어떻게 테스트 할 수 있습니까? 예 try 블록 내에서 메시지를 보내고 계속되는 예외를 잡을 수 있지만 좀 더 우아한 해결책을 기대하고 있습니다.Websphere MQ 연결 상태를 얻는 방법과 연결을 재설정하는 방법 :

2) 연결을 열거 나 닫고 다시 열려면 어떻게해야합니까? 위의 질문 1을 해결하려는 나의 시도에서 연결을 열면 connection.Close()를 호출하여 연결 팩토리에서 다른 연결을 얻을 수 없다는 것을 발견했습니다 (아래 코드 부분 참조). 오류 메시지 XMSCC0008을 수신합니다.

매우 표준적인 바닐라 MQ 구성을 사용하고 있습니다. MQAccess 작은 유틸리티 클래스이다

ISession session = MQAccess.GetSession(MQAccess.Connection); 
IDestination destination = session.CreateTopic(SubTopicName); 
Consumer = MQAccess.GetConsumer(session, destination); 
Consumer.MessageListener = new MessageListener(HandleMQSubEvent); 
MQAccess.Connection.Start(); 

을 : 여기 내 클라이언트가 연결하는 방법입니다.

는 MQAccess 코드를 추가 질문을 편집 :

public static class MQAccess 
{ 
    public static readonly MQConfigurationSectionHandler ConfigSettings; 
    public static readonly IConnectionFactory ConnectionFactory; 

    private static readonly IConnection connection; 
    public static IConnection Connection 
    { 
     get { return connection; } 
    } 

    static MQAccess() 
    { 
     ConfigSettings = (MQConfigurationSectionHandler) 
      ConfigurationManager.GetSection("mq-configuration"); 

     XMSFactoryFactory factory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ); 
     ConnectionFactory = factory.CreateConnectionFactory(); 
     ConnectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, ConfigSettings.Hostname); 
     ConnectionFactory.SetIntProperty(XMSC.WMQ_PORT, ConfigSettings.Port); 
     ConnectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, ConfigSettings.Channel); 

     if (ConfigSettings.QueueManager == string.Empty) 
     { 
      ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, ""); 
     } 
     else 
     { 
      ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, ConfigSettings.QueueManager); 
     } 

     connection = GetConnection(); 
    } 

    public static IConnection GetConnection() 
    { 
     return ConnectionFactory.CreateConnection(); 
    } 

    public static ISession GetSession(IConnection connection) 
    { 
     return connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge); 
    } 

    public static IMessageProducer GetProducer(ISession session, IDestination destination) 
    { 
     return session.CreateProducer(destination); 
    } 

    public static IMessageConsumer GetConsumer(ISession session, IDestination destination) 
    { 
     return session.CreateConsumer(destination); 
    } 

    public static void MQPub(string TopicURI, string message) 
    { 
     using (var session = GetSession(Connection)) 
     { 
      using (var destination = session.CreateTopic(TopicURI)) 
      { 
       using (var producer = GetProducer(session, destination)) 
       { 
        producer.Send(session.CreateTextMessage(message)); 
       } 
      } 
     } 
    } 

    public static void MQPub(string TopicURI, IEnumerable<string> messages) 
    { 
     using (var session = GetSession(Connection)) 
     { 
      using (var destination = session.CreateTopic(TopicURI)) 
      { 
       using (var producer = GetProducer(session, destination)) 
       { 
        foreach (var message in messages) 
        { 
         producer.Send(session.CreateTextMessage(message)); 
        } 
       } 
      } 
     } 
    } 
} 

편집 : MQClient로 이름이 변경 MQAccess 클래스를. T Rob 제안에 따라 인스턴스 클래스로 만들었습니다. 분리 방법은 여전히 ​​

public class MQClient : IDisposable 
{ 
    public MQConfigurationSectionHandler ConfigSettings { get; private set; } 
    public IConnectionFactory ConnectionFactory { get; private set; } 

    public IConnection Connection { get; private set; } 

    public IMessageConsumer Consumer { get; private set; } 
    public IMessageProducer Producer { get; private set; } 
    // Save sessions as fields for disposing and future subscription functionality 
    private ISession ProducerSession; 
    private ISession ConsumerSession; 
    public string SubTopicName { get; private set; } 
    public string PubTopicName { get; private set; } 
    public bool IsConnected { get; private set; } 
    public event Action<Exception> ConnectionError; 
    private Action<IMessage> IncomingMessageHandler; 

    public MQClient(string subTopicName, string pubTopicName, Action<IMessage> incomingMessageHandler) 
    { 
     // Dont put connect logic in the constructor. If we lose the connection we may need to connect again. 
     SubTopicName = subTopicName; 
     PubTopicName = pubTopicName; 
     IncomingMessageHandler = incomingMessageHandler; 
    } 

    public string Connect() 
    { 
     IsConnected = false; 
     string errorMsg = string.Empty; 

     ConfigSettings = (MQConfigurationSectionHandler) 
       ConfigurationManager.GetSection("mq-configuration"); 

     XMSFactoryFactory factory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ); 
     ConnectionFactory = factory.CreateConnectionFactory(); 
     ConnectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, ConfigSettings.Hostname); 
     ConnectionFactory.SetIntProperty(XMSC.WMQ_PORT, ConfigSettings.Port); 
     ConnectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, ConfigSettings.Channel); 

     if (ConfigSettings.QueueManager == string.Empty) 
      ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, ""); 
     else 
      ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, ConfigSettings.QueueManager); 

     Connection = ConnectionFactory.CreateConnection(); 


     if (!string.IsNullOrEmpty(PubTopicName)) 
     { 
      ProducerSession = Connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge); 
      Producer = ProducerSession.CreateProducer(ProducerSession.CreateTopic(PubTopicName)); 
     } 

     if (!string.IsNullOrEmpty(SubTopicName) && IncomingMessageHandler != null) 
     { 
      ConsumerSession = Connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge); 
      Consumer = ConsumerSession.CreateConsumer(ConsumerSession.CreateTopic(SubTopicName)); 
      Consumer.MessageListener = new MessageListener(IncomingMessageHandler); 
     } 

     try 
     { 
      Connection.Start(); 
      Connection.ExceptionListener = new ExceptionListener(ConnectionExceptionHandler); 
      IsConnected = true; 
     } 
     catch (TypeInitializationException ex) 
     { 
      errorMsg = "A TypeInitializationException error occured while attempting to connect to MQ. Check the Queue configuration in App.config. The error message is: " + ex.Message; 
     } 
     catch (IllegalStateException ex) 
     { 
      errorMsg = "An IllegalStateException error occured while attempting to connect to MQ. Check the Queue configuration in App.config. The error message is: " + ex.Message; 
     } 

     return errorMsg; 
    } 

    public void Disconnect() 
    { 
     if (Producer != null) 
     { 
      Producer.Close(); 
      Producer.Dispose(); 
      Producer = null; 
     } 

     if (ProducerSession != null) 
     { 
      // Call Unsubscribe here if subscription is durable 

      ProducerSession.Close(); 
      ProducerSession.Dispose(); 
      ProducerSession = null; 
     } 

     if (Connection != null) 
     { 
      Connection.Stop(); 

      //if (Connection.ExceptionListener != null) 
      // Connection.ExceptionListener = null; 

      // Per Shashi............ 
      //if (Consumer.MessageListener != null) 
      // Consumer.MessageListener = null; 

      Connection.Close(); 
      Connection.Dispose(); 
      Connection = null; 
     } 

     if (Consumer != null) 
     { 

      if (Consumer.MessageListener != null) 
       Consumer.MessageListener = null; 

      Consumer.Close(); 
      Consumer.Dispose(); 
      Consumer = null; 
     } 


     if (ConsumerSession != null) 
     { 
      // Call Unsubscribe here if subscription is durable 
      ConsumerSession.Close(); 
      ConsumerSession.Dispose(); 
      ConsumerSession = null; 
     } 

     IsConnected = false; 
    } 


    public void Publish(string message) 
    { 
     Producer.Send(ProducerSession.CreateTextMessage(message)); 
    } 


    public void Publish(string[] messages) 
    { 
     foreach (string msg in messages) 
      Publish(msg); 
    } 

    public void ConnectionExceptionHandler(Exception ex) 
    { 
     Disconnect(); // Clean up 

     if (ConnectionError != null) 
      ConnectionError(ex); 
    } 

    #region IDisposable Members 
    private bool disposed; 

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

    protected virtual void Dispose(bool disposing) 
    { 
     if (!this.disposed) 
     { 
      if (disposing) 
       Disconnect(); 

      disposed = true; 
     } 
    } 
    #endregion 

} 

답변

8

문제 위에 나열된 오류 MSG를 함께 충돌하는 것은 여기에 ->가 where MQAccess is a small utility class.

질문의 첫 번째 부분은 연결이 활성 상태인지 확인하는 방법 묻습니다. WebSphere MQ의 XMS 클래스는 비 Java 플랫폼 용 JMS 스펙의 구현입니다. 그들은 JMS 스펙을 상당히 가깝게 따르며 JMS 스펙은 연결 또는 세션에서 isConnected과 같은 메소드를 가지지 않으므로 XMS도 마찬가지입니다. 그러나 모든 GET 및 PUT 활동은 JMS 예외를 포착하기 위해 try/catch 블록 내에서 발생해야합니다. (어떤 항상linkedException을 인쇄, 오른쪽?) JMS 예외가 throw되면 응용 프로그램이 치명적인 것으로 간주하거나 죽게하거나 연결 팩토리를 제외한 모든 JMS 객체를 닫고 몇 초 기다린 다음 다시 시작합니다. 연결 순서를 유도합니다. MQAccess 클래스를 게시
감사 : 새로운 질문의 정보를 기반으로

UPDATE. 이는 문제의 파트 # 2에 따라 연결이 닫히고 다시 열리는 위치를 보여주는 코드가 아직 없지만 현재 일어나고있는 일에 대해 상당한 통찰력을 제공합니다.

그러나이 코드는 으로 공개적으로 노출 된 클래스 인스턴스가 생성 될 때 ICONNECTION connection의 개인 인스턴스를 생성한다는 것을 보여줍니다. 현재 게시 된 MQAccess 클래스에는 connection이 보유한 연결 핸들을 대체 할 공용 또는 개인 클래스 메서드가 없으므로 MQAccess.Connection.Close()이 호출되면 IConnectionMQAccess 클래스의 개체 인스턴스가 잘못된 연결 핸들을 보유하게됩니다. 연결이 닫히면 MQAccess의 해당 인스턴스가 실제로 종료됩니다. 새로운 연결을 얻으려면 MQAccess을 삭제하고 다시 시작해야합니다.

MQAccess 클래스는 심지어 원래 하나를 닫은 후, 클래스 외부에서 MQAccess.GetConnection를 호출하고 유효한 새로운 IConnection 개체를 얻을 수있을 것이다 이론 있도록 공개적으로 연결 팩토리를 노출한다.그러나, 인스턴스는 MQAccess 클래스의 범위 밖에 존재하는 것 때문에 MQAccess에 대한 후속 호출은 소멸 인스턴스 변수 connection보다는 클래스 외부에서 만든 새 연결 인스턴스를 참조한다. 당신이 닫고 연결을 다시해야하는 경우

, 당신은 그것과 내부 MQAccess의 관리를 고려할 수 있습니다. 낮은 기술 접근 ​​방식은 기존 연결을 닫을 연결에 대해 MQAccess.Close() 메서드를 작성한 다음 즉시 connection = GetConnection();을 호출하여 connection 개인 변수가 항상 유효한 연결 핸들을 보유하도록 할 수 있습니다.

이 문제가 해결되지 않으면 닫고 연결을 다시 한 코드를 게시하시기 바랍니다. 그런데

는 네트워크 연결을 통해 비 거래 세션은 WMQ을 포함한 모든 JMS 제공자에 대한 메시지를 잃거나 복제 할 수있는 가능성을 엽니 다. 이게 당신이 의도 한거야? 나는 이것이 왜 다른 사람 포스트 here에있는 지 설명했다.

+0

T Rob 감사합니다. 정말 도움이됩니다.맞습니다 - 클래스는 컨스트럭터에서 MQ를 시작하지 않아야합니다. linkedException로 무엇을 의미합니까? – Sam

+0

JMS 예외 (따라서 JMS 모델이므로 XMS 예외)는 다중 레벨 구조입니다. JMS에서 최상위 수준에는 "연결 실패"와 같은 일반적인 예외가 있지만 그 이후 수준에는 "QMgr을 찾을 수 없음"또는 "잘못된 QMgr 이름"과 같은 공급자 관련 데이터가 포함되어 있습니다. 링크 된 예외가있는 경우 진단에 도움이 될 정보가있을 것입니다. ['LinkedException'을 참조하십시오. (http://pic.dhe.ibm.com/infocenter/wmqv7/v7r5/topic/com.ibm.mq.msc.doc/sapiexcpt.html#sapiexcpt_getlkex) –

+0

오, 절대 알지도 못합니다. that linkedException은 IllegalStateException의 특성입니다. – Sam

5

T.Rob의 의견에 추가.

질문 1 :
MQAccess의 소스 코드에 액세스 할 수 있으면 좋겠습니다. 그렇다면 MQAccess에 연결이 활성화되어 있는지 여부를 나타내는 속성을 노출 할 수 있습니다. 액세스 권한이없는 경우이 클래스의 작성자에게이 속성을 추가하도록 요청해야 할 수 있습니다. 속성을 설정/재설정하려면 다음을 수행하십시오. createConnection 방법이 성공적으로 반환 후

1) 속성을 설정합니다.
2) 연결에 대한 예외 수신기를 설정하십시오.
3) 예외 처리기에서 속성을 다시 설정하십시오. 이유 코드를 점검하고 연결이 w 어지는 오류 인 경우 (XMSWMQ1107 및 링크 된 예외에 MQRC 2009가있을 수 있음) 특성을 재설정하십시오.

질문 2
closingreopening 연결 방법을 알려 주시면 도움이됩니다. 연결을 종료하는 것이 좋습니다.
1) 먼저 연결을 중지합니다. 중지().
2) 메시지 리스너를 제거하고 기본적으로 consumer.MessageListener = null을 수행하십시오.
3) 그런 다음 connection.Close()를 수행하십시오.
4) 연결이 = NULL

추가 정보 여기에 내가 테스트하는 데 사용했던 샘플입니다 마십시오.

private void OnException(Exception ex) 
    { 
     XMSException xmsex = (XMSException)ex; 
     Console.WriteLine("Got exception"); 
     // Check the error code. 
     if (xmsex.ErrorCode == "XMSWMQ1107") 
     { 
      Console.WriteLine("This is a connection broken error"); 
      stopProcessing = true; // This is a class member variable 
     } 
    } 

연결이 생성되는 방법에서 예외 수신기를 설정하십시오.

 // Create connection. 
     connectionWMQ = cf.CreateConnection(); 
     connectionWMQ.ExceptionListener = new ExceptionListener(OnException); 

연결 오류가있을 때마다 예외 리스너가 호출되고 플래그가 true로 설정됩니다. 더 이상 필요한 경우

그것은 개체를 처리하는 연습을 잘하지 않습니다. 부모 자식 관계가 있고, Consumer, Producer 등은 Connection의 자식 인 Session의 자식입니다. 따라서 처분 순서는 자녀가 먼저, 부모가 다음이 될 수 있습니다. 그러나 부모가 처분되면 어린이도 자동으로 처분됩니다.

+0

샤시 감사합니다! 내가 너무 많이 묻지 않기를 바랄 뿐이지 만, 질문 1에 답하는 것을 보여주는 예제 코드가 있습니까? XMSWMQ1107에 대한 Google 검색은이 게시물 만 나타납니다! – Sam

+0

생산자, 소비자, 세션 및 청취자를 처분해야합니까? 이 게시물을 참조하십시오 : http://stackoverflow.com/questions/12508473/ibm-mq-xms-subscription-not-closing 올바른 순서는 무엇입니까? – Sam

+0

ExceptionListener를 구현했지만 연결이 끊어지면이를 감지하지 못하므로 IsConnected 플래그가 설정되지 않습니다. – Sam