C# - dynamicport 값의 범위를 알아내는 방법
이상하군요, netsh로 수행하는,
C:\temp> netsh int ipv4 show dynamicport tcp
Protocol tcp Dynamic Port Range
---------------------------------
Start Port : 1024
Number of Ports : 64511
결과를 API로 가져올 수 있는 방법을 모르겠습니다. (혹시 Win32 API로 아시는 분은 덧글 부탁드립니다.) 그렇다고 저 출력 결과를 파싱하는 것은 왠지 자존심이 허락지 않습니다. ^^
다행히 검색해 보면, PowerShell을 통해 가져오는 방법이 있는데,
Get-NetTCPSetting
; https://learn.microsoft.com/en-us/powershell/module/nettcpip/get-nettcpsetting
테스트 PC에서 실행해 보니 다음과 같은 결과를 확인할 수 있고,
PS C:\WINDOWS\system32> Get-NetTCPSetting
SettingName : Automatic
...[생략]...
SettingName : InternetCustom
MinRto(ms) : 300
InitialCongestionWindow(MSS) : 10
CongestionProvider : CUBIC
CwndRestart : False
DelayedAckTimeout(ms) : 40
DelayedAckFrequency : 2
MemoryPressureProtection : Enabled
AutoTuningLevelLocal : Normal
AutoTuningLevelGroupPolicy : NotConfigured
AutoTuningLevelEffective : Local
EcnCapability : Disabled
Timestamps : Disabled
InitialRto(ms) : 1000
ScalingHeuristics : Disabled
DynamicPortRangeStartPort : 1024
DynamicPortRangeNumberOfPorts : 64511
AutomaticUseCustom : Disabled
NonSackRttResiliency : Disabled
ForceWS : Enabled
MaxSynRetransmissions : 4
AutoReusePortRangeStartPort : 0
AutoReusePortRangeNumberOfPorts : 0
SettingName : DatacenterCustom
MinRto(ms) : 20
InitialCongestionWindow(MSS) : 10
CongestionProvider : CUBIC
CwndRestart : False
DelayedAckTimeout(ms) : 10
DelayedAckFrequency : 2
MemoryPressureProtection : Enabled
AutoTuningLevelLocal : Normal
AutoTuningLevelGroupPolicy : NotConfigured
AutoTuningLevelEffective : Local
EcnCapability : Disabled
Timestamps : Disabled
InitialRto(ms) : 1000
ScalingHeuristics : Disabled
DynamicPortRangeStartPort : 1024
DynamicPortRangeNumberOfPorts : 64511
AutomaticUseCustom : Disabled
NonSackRttResiliency : Disabled
ForceWS : Enabled
MaxSynRetransmissions : 4
AutoReusePortRangeStartPort : 0
AutoReusePortRangeNumberOfPorts : 0
SettingName : Compat
MinRto(ms) : 300
InitialCongestionWindow(MSS) : 4
CongestionProvider : NewReno
CwndRestart : False
DelayedAckTimeout(ms) : 200
DelayedAckFrequency : 2
MemoryPressureProtection : Enabled
AutoTuningLevelLocal : Normal
AutoTuningLevelGroupPolicy : NotConfigured
AutoTuningLevelEffective : Local
EcnCapability : Disabled
Timestamps : Disabled
InitialRto(ms) : 1000
ScalingHeuristics : Disabled
DynamicPortRangeStartPort : 1024
DynamicPortRangeNumberOfPorts : 64511
AutomaticUseCustom : Disabled
NonSackRttResiliency : Disabled
ForceWS : Enabled
MaxSynRetransmissions : 4
AutoReusePortRangeStartPort : 0
AutoReusePortRangeNumberOfPorts : 0
SettingName : Datacenter
MinRto(ms) : 20
InitialCongestionWindow(MSS) : 10
CongestionProvider : CUBIC
CwndRestart : False
DelayedAckTimeout(ms) : 10
DelayedAckFrequency : 2
MemoryPressureProtection : Enabled
AutoTuningLevelLocal : Normal
AutoTuningLevelGroupPolicy : NotConfigured
AutoTuningLevelEffective : Local
EcnCapability : Disabled
Timestamps : Disabled
InitialRto(ms) : 1000
ScalingHeuristics : Disabled
DynamicPortRangeStartPort : 1024
DynamicPortRangeNumberOfPorts : 64511
AutomaticUseCustom : Disabled
NonSackRttResiliency : Disabled
ForceWS : Enabled
MaxSynRetransmissions : 4
AutoReusePortRangeStartPort : 0
AutoReusePortRangeNumberOfPorts : 0
SettingName : Internet
MinRto(ms) : 300
InitialCongestionWindow(MSS) : 10
CongestionProvider : CUBIC
CwndRestart : False
DelayedAckTimeout(ms) : 40
DelayedAckFrequency : 2
MemoryPressureProtection : Enabled
AutoTuningLevelLocal : Normal
AutoTuningLevelGroupPolicy : NotConfigured
AutoTuningLevelEffective : Local
EcnCapability : Disabled
Timestamps : Disabled
InitialRto(ms) : 1000
ScalingHeuristics : Disabled
DynamicPortRangeStartPort : 1024
DynamicPortRangeNumberOfPorts : 64511
AutomaticUseCustom : Disabled
NonSackRttResiliency : Disabled
ForceWS : Enabled
MaxSynRetransmissions : 4
AutoReusePortRangeStartPort : 0
AutoReusePortRangeNumberOfPorts : 0
따라서 "netsh ..." 명령어의 출력 결과를 파싱하는 것보다 C#에서 Powershell 스크립트를 호출할 수 있으므로,
How to call Powershell script using web API (cs or asp.net)
; https://stackoverflow.com/questions/54523708/how-to-call-powershell-script-using-web-api-cs-or-asp-net
Executing PowerShell scripts from C#
; https://learn.microsoft.com/en-us/archive/blogs/kebab/executing-powershell-scripts-from-c
다음과 같이 처리해 줄 수 있습니다.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Text;
namespace ConsoleApp1
{
// 참조 추가: C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll
// 또는, Install-Package System.Management.Automation
class Program
{
static void Main(string[] args)
{
// PowerShell
using (PowerShell instance = PowerShell.Create())
{
instance.AddCommand("Get-NetTCPSetting");
Collection<PSObject> psOutput = instance.Invoke();
foreach (PSObject obj in psOutput)
{
Console.WriteLine(obj);
}
}
}
}
}
/* 출력 결과
MSFT_NetTCPSetting (CreationClassName = "", PolicyActionName = "", PolicyRuleCreationClassName = "", PolicyRuleName = "Automatic", SystemCreationClassName = "", SystemName = "")
MSFT_NetTCPSetting (CreationClassName = "", PolicyActionName = "", PolicyRuleCreationClassName = "", PolicyRuleName = "InternetCustom", SystemCreationClassName = "", SystemName = "")
MSFT_NetTCPSetting (CreationClassName = "", PolicyActionName = "", PolicyRuleCreationClassName = "", PolicyRuleName = "DatacenterCustom", SystemCreationClassName = "", SystemName = "")
MSFT_NetTCPSetting (CreationClassName = "", PolicyActionName = "", PolicyRuleCreationClassName = "", PolicyRuleName = "Compat", SystemCreationClassName = "", SystemName = "")
MSFT_NetTCPSetting (CreationClassName = "", PolicyActionName = "", PolicyRuleCreationClassName = "", PolicyRuleName = "Datacenter", SystemCreationClassName = "", SystemName = "")
MSFT_NetTCPSetting (CreationClassName = "", PolicyActionName = "", PolicyRuleCreationClassName = "", PolicyRuleName = "Internet", SystemCreationClassName = "", SystemName = "")
*/
그런데, 출력 결과를 보면 왠지 낯이 익는 네이밍 룰이 나옵니다. "MSFT_NetTCPSetting" 이름에서 WMI의 느낌이 나는데요, 실제로 검색해 보면 이에 대한 항목을 찾을 수 있습니다.
MSFT_NetTCPSetting class
; https://learn.microsoft.com/en-us/previous-versions/windows/desktop/nettcpipprov/msft-nettcpsetting
간단하게
wmic를 이용해 빠르게 동작 여부를 확인해 보면,
C:\Windows\System32> wmic /NAMESPACE:\\root\StandardCimv2 path MSFT_NetTCPSetting where "SettingName='Internet'" get DynamicPortRangeStartPort
DynamicPortRangeStartPort
1024
게임 끝이군요, ^^ 이제 최종적으로 "System.Management.dll"만 참조 추가해 다음과 같이 코딩할 수 있습니다.
using System;
using System.Management;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
ManagementScope scope = new ManagementScope("\\\\.\\ROOT\\StandardCimv2");
ObjectQuery query = new ObjectQuery("SELECT * FROM MSFT_NetTCPSetting Where SettingName=\"Internet\"");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
Console.WriteLine("DynamicPortRangeStartPort : {0}", m["DynamicPortRangeStartPort"]);
Console.WriteLine("DynamicPortRangeNumberOfPorts : {0}", m["DynamicPortRangeNumberOfPorts"]);
}
}
}
}
/* 출력 결과
DynamicPortRangeStartPort : 1024
DynamicPortRangeNumberOfPorts : 64511
*/
참고로, MSFT_NetTCPSetting에서 다양하게 나오는 PolicyRuleName(또는 SettingName)에 대해 궁금하다면 다음의 글을 추천합니다.
TCP Templates for Windows Server 2019 - How to tune your Windows Server Transports (Advanced users only)
; https://argonsys.com/microsoft-cloud/library/tcp-templates-for-windows-server-2019-how-to-tune-your-windows-server-transports-advanced-users-only-%F0%9F%98%89/
저런 게 있는 줄 저도 처음 알았습니다. ^^
그건 그렇고, 점점 더 이야기가 재미있어지지 않나요? ^^ Get-NetTCPSetting의 결과를 자세하게 살펴보면 그동안 아래의 시리즈 글에서 고민했던,
윈도우 환경에서 클라이언트 소켓의 최대 접속 수
; https://www.sysnet.pe.kr/2/0/12350
윈도우 환경에서 클라이언트 소켓의 최대 접속 수 (2) - SO_REUSEADDR
; https://www.sysnet.pe.kr/2/0/12432
윈도우 환경에서 클라이언트 소켓의 최대 접속 수 (3) - SO_PORT_SCALABILITY
; https://www.sysnet.pe.kr/2/0/12433
그 문제를 한 방에 날려버릴 단서가 있습니다. 그 이야기는
다음번 포스트에서. ^^
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]