使用C#取得Client端非IPv6的IP(非::1或127.0.0.1)

當在本機用VisualStudio開發ASP.NET網站時,常常會遇到用使用System.Web.HttpContext.Current.Request.UserHostAddress;時,就會遇到回傳本機IP的問題(通常是::1或127.0.0.1),這會讓一些針對IP所進行的判斷程序出現異常,因此這一篇文章就是要討論有關於這方面的解決方案。

透過C#取得本機端的真實IP

在.NET的System.Net.Dns命名空間中,存在著可以存取到本機所有IP的方法,因此我在Console中寫下下列的範例程式,供給大家參考。

using System;
using System.Linq;
using static System.Console;
namespace Simply
{
	class Program
	{
		public static void Main()
		{
			foreach (var oItem in ClientIP.getList)
			{
				WriteLine("是否為私有:" + oItem.bIsPrivate);
				WriteLine("是否為本機:" + oItem.bIsLocal);
				WriteLine("是否為IPv6:" + oItem.bIsIPv6);
				WriteLine("IP位址:" + oItem.cValue);
				WriteLine("-----");
			}
			Read();
		}
	}

	/// 
	/// 取得Client端IP類別
	/// 
	public class ClientIP
	{
		public static System.Collections.Generic.List getList
		{
			get
			{
				System.Collections.Generic.List oData = new System.Collections.Generic.List();
				System.Net.IPHostEntry oClient = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
				foreach (System.Net.IPAddress oItem in oClient.AddressList)
				{
					oData.Add(new IP()
					{
						bIsPrivate = IsPrivate(oItem),
						bIsLocal = IsLocal(oItem),
						bIsIPv6 = (oItem.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) ? true : false,
						cValue = oItem.ToString()
					});
				}
				return oData;
			}
		}

		/// 
		/// 檢查是否為私有IP
		/// 
		private static bool IsPrivate(System.Net.IPAddress oIPAddress)
		{
			//如果不是IPv4就踢出去
			if (oIPAddress.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) { return false; }
			int[] iIP;
			try
			{ //分割並利用LINQ驗證IP正確性
				iIP = oIPAddress.ToString().Split(new String[] { "." }, StringSplitOptions.RemoveEmptyEntries).Select(s => int.Parse(s)).ToArray();
			}
			catch
			{ //如果有出錯一律回傳false
				return false;
			}
			//判斷是否為私有IP
			if
			(
				(iIP[0] == 10) ||
				(iIP[0] == 192 && iIP[1] == 168) ||
				(iIP[0] == 172 && (iIP[1] >= 16 && iIP[1] <= 31))
			)
			{ return true; }
			else
			{ return false; }
		}

		private static bool IsLocal(System.Net.IPAddress oIPAddress)
		{
			if (oIPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
			{
				if (oIPAddress.ToString().IndexOf("127.0.0.1, ::1") != -1)
				{ return true; }
				else
				{ return false; }
			}
			else
			{
				if (oIPAddress.IsIPv6LinkLocal || oIPAddress.IsIPv6SiteLocal || oIPAddress.IsIPv6Multicast)
				{ return true; }
				else
				{ return false; }
			}
		}
	}

	/// 
	/// IP ORM類別
	/// 
	public class IP
	{
		public bool bIsPrivate;	//是否為私有(只有在IPv4時,才有可能為True)
		public bool bIsLocal;   //是否為本機IP
		public bool bIsIPv6;    //是否為IPv6
		public string cValue;		//IP位址
	}
}

基本上我已經建立起一個類別叫做IP,所以你可以從IP中去拿到是否為私有IP?是否為IPv6?並且將其排除

除了很特別的情況,不然基本上你應該可以很順利的把本機的IPv4的真實IP值抓出來了。

程式運行畫面如下:

備註:有一些網站會介紹一些程式碼,用System.Net.Dns下面所屬的方法,利用IP或HostName來尋訪主機的網卡(例如上面的程式碼範例),藉以用Linq取出(或稱為轉換)::1、127.0.0.1或是一些延伸判斷。要注意的是這些論點都是基於你的主機網卡非常的乾淨,也就是網卡數量可能只有一片而定,若你的機器上面有很多網卡(例如虛擬網卡),那這樣的方式根本行不通的,因為你根本不知道你會抓到哪一片網卡所屬的私有IP,這樣不穩定、因環境而設事的做法,其實毫無道理可言。

C# ASP.NET IIS IP IPv4 IPv6 LocalHost ::1 127.0.0.1