using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; /// /// 활성 네트워크 어댑터의 IPv4 주소를 열거하고, 선호 주소를 해석하는 유틸리티. /// PC에 NIC이 여러 개(유선/무선/Hyper-V/VPN 등)일 때 서버가 사용/표시할 IP를 /// 사용자가 명시적으로 고를 수 있도록 돕는다. /// public static class NetworkInterfaceUtil { public struct Adapter { public string name; // 어댑터 이름 (예: "이더넷", "Wi-Fi") public string ip; // IPv4 주소 문자열 } /// /// 활성(Up) IPv4 어댑터 목록을 반환한다. 루프백/APIPA(169.254.x.x)는 제외. /// 기본 게이트웨이가 있는 어댑터(실제 LAN/인터넷 연결)를 앞쪽에 정렬하여 /// Hyper-V/VPN 같은 가상 어댑터보다 우선 노출한다. /// public static List GetAdapters() { var withGateway = new List(); var withoutGateway = new List(); try { foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) { if (ni.OperationalStatus != OperationalStatus.Up) continue; if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue; var props = ni.GetIPProperties(); bool hasGateway = props.GatewayAddresses.Any(g => g.Address != null && g.Address.AddressFamily == AddressFamily.InterNetwork && !g.Address.Equals(IPAddress.Any)); foreach (var addr in props.UnicastAddresses) { if (addr.Address.AddressFamily != AddressFamily.InterNetwork) continue; if (IPAddress.IsLoopback(addr.Address)) continue; byte[] b = addr.Address.GetAddressBytes(); if (b[0] == 169 && b[1] == 254) continue; // APIPA(자동 사설 IP) 제외 var adapter = new Adapter { name = ni.Name, ip = addr.Address.ToString() }; (hasGateway ? withGateway : withoutGateway).Add(adapter); } } } catch { } withGateway.AddRange(withoutGateway); return withGateway; } /// /// 선호 주소(preferred)가 현재 유효한 어댑터 IP면 그대로 사용하고, /// 비었거나 더 이상 존재하지 않으면 자동 선택(첫 번째 = 게이트웨이 우선)한다. /// 사용 가능한 IPv4가 전혀 없으면 빈 문자열. /// public static string ResolveHostAddress(string preferred) { var adapters = GetAdapters(); if (!string.IsNullOrEmpty(preferred) && adapters.Any(a => a.ip == preferred)) return preferred; return adapters.Count > 0 ? adapters[0].ip : ""; } }