.NET 5부터 지원하는 GetRawSocketOption 사용 시 주의할 점
대개의 경우, 사용이 편리하기 때문에 GetRawSocketOption보다는 GetSocketOption을 사용하게 될 것입니다. 예를 들어, KeepAlive 상태 값을 구하는 경우 이렇게 코딩할 수 있습니다.
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine(socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive)); // TcpKeepAliveInterval, TcpKeepAliveTime
return;
// 출력 결과: 0
그런데, .NET 5부터 지원하는 GetRawSocketOption 메서드는,
Socket.GetRawSocketOption(Int32, Int32, Span<Byte>) Method
; https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.getrawsocketoption
인자에
SocketOptionLevel,
SocketOptionName enum 타입을 받지 않고 직접 int 값을 전달해야 합니다. 가령 위에서 KeepAlive를 구하기 위해 전달한 SocketOptionLevel.Socket, SocketOptionName.KeepAlive에 대해 각각 상숫값 그대로 다음과 같이 바꿔 코딩할 수 있는데요,
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
byte[] buffer = new byte[4];
// SocketOptionLevel.Socket == 0xffff
// SocketOptionName.KeepAlive == 8
int nbytes = socket.GetRawSocketOption(0xffff, 8, buffer);
int keepAlive = BitConverter.ToInt32(buffer, 0);
Console.WriteLine($"SO_KEEPALIVE: {keepAlive}");
/* 출력 결과
0
SO_KEEPALIVE: 0
*/
문제는, 이 값이 플랫폼별로 다르다는 점입니다. 그래서 위의 소스 코드로 WSL 환경에서 실행하면 이런 예외가 발생합니다.
Unhandled exception. System.Net.Sockets.SocketException (95): Operation not supported
at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
at System.Net.Sockets.Socket.GetRawSocketOption(Int32 optionLevel, Int32 optionName, Span`1 optionValue)
at ConsoleApp1.Program.Main(String[] args) in C:\temp\ConsoleApp1\ConsoleApp1\Program.cs:line 45
따라서, 이 소스 코드를 정상적으로 동작하게 만들려면 SOL_SOCKET == 1, SO_KEEPALIVE == 9로 설정해서,
/*
sys/socket.h
#define SOL_SOCKET 1
#define SO_KEEPALIVE 9
*/
int nbytes = socket.GetRawSocketOption(1, 9, buffer);
실행해야 합니다. 그렇기 때문에 GetSocketOption에서 지원되는 옵션이라면 가능한 그것을 사용하고, 만약 지원되지 않아 GetRawSocketOption을 사용한다면 다중 플랫폼 지원에 따른 고려를 해야 합니다.
제 생각에는, 대충 이런 식으로 코딩을 하는 것이 좋겠습니다. ^^
using System.Net.Sockets;
using System.Runtime.InteropServices;
internal class Program
{
public static int SOL_SOCKET
{
get
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return 0xffff;
}
return 1;
}
}
public static int SO_KEEPALIVE
{
get
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return 8;
}
return 9;
}
}
static void Main(string[] args)
{
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine(socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive));
}
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
byte[] buffer = new byte[4];
socket.GetRawSocketOption(SOL_SOCKET, SO_KEEPALIVE, buffer);
int keepAlive = BitConverter.ToInt32(buffer, 0);
Console.WriteLine($"SO_KEEPALIVE: {keepAlive}");
}
}
}
아쉽군요, 왜 플랫폼마다 다르게 저 상숫값들이 정해졌을까요? ^^;
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]