HTTP는 기본적으로 요청과 응답 후 연결을 종료하는 비지속적 프로토콜이지만, 성능 향상을 위해 동일한 TCP 연결을 재사용하는 지속 연결(Persistent Connection) 방식을 지원한다. 이 기능은 특히 HTTP/1.1에서 기본으로 활성화되며, 클라이언트와 서버 간 반복적인 통신 시 연결 설정 오버헤드를 줄이는 데 효과적이다. 그러나 네트워크 장애나 중간 장비에 의해 연결이 예기치 않게 끊길 수 있으므로, 유휨한 연결 상태를 유지하기 위한 추가적인 메커니즘이 필요하다. 이때 사용되는 것이 TCP Keep-Alive이다.
TCP Keep-Alive는 일정 시간 동안 데이터가 송수신되지 않은 연결에 대해 주기적으로 "핑" 신호를 보내 피어(peer)의 존재 여부를 확인하는 기능이다. .NET에서는 Socket.IOControl 메서드를 통해 이 기능의 동작 파라미터를 직접 제어할 수 있다. 이를 위해서는 Windows Sockets에서 정의하는 tcp_keepalive 구조체를 P/Invoke 또는 메모리 레이아웃 조작을 통해 C#에서 표현해야 한다.
다음은 C 언어의 tcp_keepalive 구조체를 C#에서 unsafe 코드를 사용해 매핑한 예시이다:
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
unsafe struct TcpKeepAliveConfig
{
public uint Enable;
public uint TimeMs;
public uint IntervalMs;
public TcpKeepAliveConfig(bool enable, uint timeMilliseconds, uint intervalMilliseconds)
{
Enable = enable ? 1u : 0;
TimeMs = timeMilliseconds;
IntervalMs = intervalMilliseconds;
}
}
이 구조체를 기반으로 소켓에 Keep-Alive 값을 설정하는 메서드를 작성할 수 있다:
public static int ConfigureTcpKeepAlive(System.Net.Sockets.Socket socket, bool enabled, uint keepAliveTimeMs, uint keepAliveIntervalMs)
{
if (socket == null) throw new ArgumentNullException(nameof(socket));
const uint SIO_KEEPALIVE_VALS = unchecked((uint)0x98000004);
var config = new TcpKeepAliveConfig(enabled, keepAliveTimeMs, keepAliveIntervalMs);
byte[] inValue = new byte[12];
// 수동으로 바이트 배열 채우기 (little-endian)
Buffer.BlockCopy(BitConverter.GetBytes(config.Enable), 0, inValue, 0, 4);
Buffer.BlockCopy(BitConverter.GetBytes(config.TimeMs), 0, inValue, 4, 4);
Buffer.BlockCopy(BitConverter.GetBytes(config.IntervalMs), 0, inValue, 8, 4);
return socket.IOControl((System.Net.Sockets.IOControlCode)(long)SIO_KEEPALIVE_VALS, inValue, null);
}
위 메서드를 사용하여 특정 소켓에 Keep-Alive를 활성화하고, 2시간 후 첫 번째 프로브를 전송하며, 이후 1초 간격으로 재시도하도록 설정할 수 있다:
var clientSocket = new System.Net.Sockets.Socket(
System.Net.Sockets.AddressFamily.InterNetwork,
System.Net.Sockets.SocketType.Stream,
System.Net.Sockets.ProtocolType.Tcp
);
// 연결 후 또는 연결 전에 설정 가능
ConfigureTcpKeepAlive(clientSocket, true, 7200000, 1000); // 2시간 대기, 1초 간격
이 설정은 운영체제 수준에서 TCP 스택에 의해 처리되며, 애플리케이션 로직에 개입하지 않고도 장기간 유휸하지 않는 연결의 상태를 감시할 수 있게 한다. 특히 IoT 장치나 장기 실행 클라이언트 애플리케이션에서 유용하게 활용된다.