* 아래 글은 작성자의 학습을 토대로 이해한 내용을 작성하였기 때문에 사실과 다른 부분이 있을 수 있습니다.
C# 네트워크 프로그램을 작성하다 보면 연결 상태를 체크해야 하는 경우가 있다.
Socket의 속성 IsConnected를 사용하면 될 것 같지만 그렇지 못했다.
IsConnected는 현재 시점에서의 연결 상태가 아닌 바로 이전 전송을 기준으로 연결 상태 값이 설정되기 때문이다.
예를 들어 설명하면
마지막 전송이 성공했다면 IsConnected는 true상태일 것이다.
네트워크 상태가 불안정하여 Connected 상태가 변경되었을 때에도 IsConnected는 여전히 true 상태로 남아있게 된다.
다시 말해 IsConnected 속성은 현재의 연결 상태를 바로바로 반영해주는 속성이 아니라는 것이다.
이를 해결하기 위해 구글링 한 결과 ----------------------------------------------------
1. TimeOut을 이용 --> 예제가 복잡해 보이고 어떻게 하는지도 잘 모르겠어서 패스
2. TcpConnectionInformation 이용 --> 비교적 간단한 예제를 찾을 수 있어서 활용!
--------------------------------------------------------------------------------------------
2번째 방법을 사용해 현재 시점의 연결 상태를 점검하는 기능을 구현하였다.
IPGlobalProperties 객체의 GetActiveTcpConnections()를 호출하면 로컬 PC에 연결된 모든 TCP 커넥션 정보를 가져온다.
하지만 나에게 필요한 것은 특정 IP(+Port)와의 통신 상태 여부이므로 Where 문을 사용해서 나의 끝점과 연결된 곳의 끝점의 연결 정보로 제한한다.
TcpState의 경우 디테일한 TcpState Enum을 표현할 수 있는데 여기에서는 연결되어서 데이터를 주고받을 수 있는 상태를 가리키는 Established 상태만 판별하면 되기 때문에 조건을 위와 같이 주면 된다.
TcpClient 객체에서 Disconnect() 를 호출한 후 위 코드를 호출하면 nullException 예외가 발생 하였다.
아마 추가로 조건문이나 예외처리를 해줘야 하는 것 같다.
(사실 위 코드를 사용한지가 오래 돼서 정확히 기억이 잘 안남. 나중에 확인 후 예외처리 방법도 추가 하겠음. 나의 경우는 Disconnect() 호출이 꼭 필요하지 않아서 사용하는 데 문제가 없었다.)
위 코드 전체를 그대로 사용할 수도 있지만 때로는 자신의 상황에 맞게 수정해야 할지도 모른다.
핵심적으로 구현해야 하는 내용 ---------------------------------------------------
1. IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
=> 로컬 PC의 ip 정보 관련한 IPGlobalProperties 객체를 얻어올 것
-----------------------------------------------------------------------------------------------
2. TcpConnectionInformation[] tcpConnections;
=> Tcp 상태 정보를 얻어 올 TcpConnectionInformation 배열을 선언
-----------------------------------------------------------------------------------------------
3. tcpConnections = ipProperties.GetActiveTcpConnections()
Socket의 속성 IsConnected를 사용하면 될 것 같지만 그렇지 못했다.
IsConnected는 현재 시점에서의 연결 상태가 아닌 바로 이전 전송을 기준으로 연결 상태 값이 설정되기 때문이다.
예를 들어 설명하면
마지막 전송이 성공했다면 IsConnected는 true상태일 것이다.
네트워크 상태가 불안정하여 Connected 상태가 변경되었을 때에도 IsConnected는 여전히 true 상태로 남아있게 된다.
다시 말해 IsConnected 속성은 현재의 연결 상태를 바로바로 반영해주는 속성이 아니라는 것이다.
이를 해결하기 위해 구글링 한 결과 ----------------------------------------------------
1. TimeOut을 이용 --> 예제가 복잡해 보이고 어떻게 하는지도 잘 모르겠어서 패스
2. TcpConnectionInformation 이용 --> 비교적 간단한 예제를 찾을 수 있어서 활용!
--------------------------------------------------------------------------------------------
2번째 방법을 사용해 현재 시점의 연결 상태를 점검하는 기능을 구현하였다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// 연결 상태 체크 TcpClient형의 객체명 : tcpClient
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections;
try{
tcpConnections = ipProperties.GetActiveTcpConnections()
.Where(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint) &&
x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint))
.ToArray();
}catch{
// Exception 처리 -> 여기서는 Disconnected된 것으로 보면 된다.
}
if (tcpConnections != null && tcpConnections.Length > 0)
{
TcpState stateOfConnection = tcpConnections.First().State;
if (stateOfConnection == TcpState.Established)
//Connected ~~
else
//Disconnected ~~
}
| cs |
IPGlobalProperties 객체의 GetActiveTcpConnections()를 호출하면 로컬 PC에 연결된 모든 TCP 커넥션 정보를 가져온다.
하지만 나에게 필요한 것은 특정 IP(+Port)와의 통신 상태 여부이므로 Where 문을 사용해서 나의 끝점과 연결된 곳의 끝점의 연결 정보로 제한한다.
TcpState의 경우 디테일한 TcpState Enum을 표현할 수 있는데 여기에서는 연결되어서 데이터를 주고받을 수 있는 상태를 가리키는 Established 상태만 판별하면 되기 때문에 조건을 위와 같이 주면 된다.
But!!
나의 경우 위 코드를 주기적으로 호출하도록 했는데TcpClient 객체에서 Disconnect() 를 호출한 후 위 코드를 호출하면 nullException 예외가 발생 하였다.
아마 추가로 조건문이나 예외처리를 해줘야 하는 것 같다.
(사실 위 코드를 사용한지가 오래 돼서 정확히 기억이 잘 안남. 나중에 확인 후 예외처리 방법도 추가 하겠음. 나의 경우는 Disconnect() 호출이 꼭 필요하지 않아서 사용하는 데 문제가 없었다.)
위 코드 전체를 그대로 사용할 수도 있지만 때로는 자신의 상황에 맞게 수정해야 할지도 모른다.
핵심적으로 구현해야 하는 내용 ---------------------------------------------------
1. IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
=> 로컬 PC의 ip 정보 관련한 IPGlobalProperties 객체를 얻어올 것
-----------------------------------------------------------------------------------------------
2. TcpConnectionInformation[] tcpConnections;
=> Tcp 상태 정보를 얻어 올 TcpConnectionInformation 배열을 선언
-----------------------------------------------------------------------------------------------
3. tcpConnections = ipProperties.GetActiveTcpConnections()
.Where(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint) &&
x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint))
.ToArray();
=> GetIPGlobalProperties()로 내가 원하는 조건에 부합하는 연결을 필터링해서 tcpConnectionInformation형 배열에 할당
-----------------------------------------------------------------------------------------------
위의 내용만 잘 숙지하면 간단한 활용은 무난할 것이다.
이 글에서 사용한 클래스 및 자세한 구조에 대해서는 나중에 추가로 작성하겠다.
이 글에서 사용한 클래스 및 자세한 구조에 대해서는 나중에 추가로 작성하겠다.
감사합니다. 매우 잘되네요!
답글삭제TcpState Enum 정보를 캐스팅이 되지 않는데요 어떻게 해야 하나요?
답글삭제if (tcpConnections != null && tcpConnections.Length > 0)
{
TcpState stateOfConnection = tcpConnections.First().State;
// var cod = Enum.Parse(TcpState, "Established");
var Established = (TcpState).5;
if (stateOfConnection == Established) //Established
{
isOpen = true;
}
else
{
isOpen = false; //Disconnected ~~
}
}
그래서 결국 이렇게 시도 해봤어요
TcpState.Established 이것이 캐스팅이 되지 않는 걸까요?
답글삭제앗 해결을 했어요 변수명이 같아서 ...ㅎㅎ
답글삭제