본문 바로가기
인생은 실전/C#

[C#] TCP - 비동기로 TCP 원격 호스트 연결 상태 확인하기 / TcpClient.BeginConnect / ManualResetEvent.WaitOne / ManualResetEvent.Set

by 나는영하 2024. 1. 26.

 TCP - 비동기로 TCP 원격 호스트 연결 상태 확인하기

 

Kafka나 RabbitMQ 여타 다른 미들웨어는 대부분 TCP/IP 통신을 통해 데이터를 주고 받는다.
따라서 통신을 위해 사전에 해당 호스트 TCP 연결하기 전에 상대 네트워크의 상태를 확인해주는 로직 필요로 하는 경우가 있다. (연결이 되어 있지도 않은데 무작정 Kafka 설정을 한다거나 데이터를 보낼순 없으니까..😂)

 

따라서 Driver 인스턴스를 생성하고 안에 Connect 메서드를 호출할때 if문을 통해 네트워크 상태를 확인한다.

if(CheckNetworkState()){

  • Driver Setting
  • Event 연결
  • Timmer 실행 Driver 연결에 대한 주요 로직

}

이럴때 쓰기 좋은게 TcpClient.BeginConnect 메서드와 ManualResetEvent 클래스 이다.

 

 TcpClient.BeginConnect / ManualResetEvent.WaitOne & Set

TcpClient.BeginConnect 메서드는 연결에 대한 비동기 요청을 보내고 작업이 완료되면 세번째 인자에 등록하는 메서드를 호출하는 방식이다. 

해당 메서드의 오버로드는 3개로 아래와 같다.

 

3번째 인자로 사용되는 AsyncCallback 인자는 [ new AsyncCallback(CallBackMethod) ]

이렇게 사용하며 해당 비동기 작업을 완료할 호출되는 메서드를 참조한다.

 

아래는 위에서 언급한 CheckNetworkState 매서드의 Sample에 해당한다.

private bool CheckNetworkState()
{
    bool isConnect = false;

    try
    {
        this.tcpClient = new TcpClient();
        this.tcpClient.NoDelay = true;

        this.tcpClient.BeginConnect(this.config.IpAddress, this.config.Port, new AsyncCallback(CallBackMethod), this.tcpClient);
        Thread.Sleep(100);
        if (ManualResetEvent.WaitOne(this.config.RetryTime * 1000, false))      // 동기화시킨다. timeoutMSec 동안 기다린다.
        {
            if (IsConnectionSuccessful)     // 접속되는 소켓을67
            {
                isConnect = IsConnectionSuccessful;
            }
        }
    }
    catch
    {
    }
    finally
    {
        if (this.tcpClient != null)
        {
            this.tcpClient.Close();
            this.tcpClient = null;
        }
    }

    return isConnect;
}

 


 

CallBackMethod는 비동기 작업상태를 bool 값으로 리턴해주고 해당 작업이 수행되고 있는 동안 멈춰있는 다른 스레드의 동작을 수행시켜주는 로직에 해당된다. 

 

CallBackMethod의 Sample은 아래와 같다. 

 private void CallBackMethod(IAsyncResult asyncresult)
 {
     try
     {
         IsConnectionSuccessful = false;

         TcpClient tcpclient = asyncresult.AsyncState as TcpClient;

         if (tcpclient.Client != null)
         {
             tcpclient.EndConnect(asyncresult);
             IsConnectionSuccessful = true;
         }
     }
     catch (Exception ex)
     {
         IsConnectionSuccessful = false;
     }
     finally
     {
         ManualResetEvent.Set();
     }
 }

 

콜백 메서드에 있는 인자는 IAsyncResult로 비동기 작업 상태의 결과를 나타낸다.

비동기 작업에 대한 정보를 가지고 있는 AsyncState 속성을 as연산자를 통해 TcpClient로 변환한다.

따라서 비동기 작업(TcpClient와 연결)이 성공적으로 수행되었다면 정상적으로 TcpClient로 변환이 될테고 if문을 정상적으로 수행하게 될 것이다(bool 값은 true로 return). 

 

finally에 있는 ManualResetEvent.set 메서드는 해당 비동기 작업이 수행되는 동안 잠시 대기하고 있는 스레드가 다시 진행되도록 하는 메서드에 해당한다.

ManualResetEvent.WaitOne() 메서드에서 일정 시간동안 해당 스레드가 대기하게 되는데 저 Set메서드가 실행되면 대기하던 스레드가 다시 실행된다.

따라서 ManualResetEvent.WaitOne 메서드와 ManualResetEvent.Set 메서드는 짝꿍!!!(Reset 메서드도 포함, 다시 해당 스레드를 대기하도록 하는 메서드)

 

 

※응용 : Timer와 결합해서 일정 주기로 네트워크 연결상태를 확인해 연결을 해제(Disconnect) 하거나 다시 Timer를 동작시키는 방법으로 네트워크 상태를 주기적으로 확인 할 수 있다.

댓글