1. 程式人生 > 程式設計 >如何用C#驗證IP是否為區域網地址

如何用C#驗證IP是否為區域網地址

前一陣子有【廣州.NET群】的客戶問起這個問題,說他們需要驗證客戶輸入的網站是否為區域網。其實區域網的IP並沒有確定的定義,只要是區域網中,即可設定為任何一個IP。

但確實存在一個內網保留地址的定義,它會確保公網IPv4的地址不會分配在“內網保留地址”中,該地址定義如下:

10.0.0.0/8,即10.0.0.0-10.255.255.255;
172.16.0.0/12,即172.16.0.0-172.31.255.255;
192.168.0.0/16,即192.168.0.0-192.168.255.255。

客戶澄清,他確實就是想驗證IPv4字串是否為內網保留地址。

下面我們來想想幾種驗證IPv4地址字串是否為內網保留地址的方法。

首先寫出該方法的簽名:

bool IsPrivateNetwork(string ipv4Address)
{
}

然後構建測試資料,顯示期待結果:

var testData = new Dictionary<string,bool>
{
	[""] = false,["Not A IP"] = false,["225.5.5.5"] = false,["175.10.74.64"] = false,["192.168.1.13"] = true,["10.10.24.220"] = true,["172.24.1.120"] = true,["172.32.1.120"] = false,};

string output = String.Join("\r\n",testData.Select(x => $"[{x.Key,12}] Expected: {x.Value,5},\tActual: {IsPrivateNetwork(x.Key),5}"));
	
Console.WriteLine(output);

方法1——StartsWith()

這是最容易想到的方法,用字串的Substring、StartsWith等方式來實現:

bool IsPrivateNetwork(string ipv4Address)
{
	if (IPAddress.TryParse(ipv4Address,out _))
	{
		if (ipv4Address.StartsWith("192.168.") || ipv4Address.StartsWith("10."))
		{
			return true;
		}

		if (ipv4Address.StartsWith("172."))
		{
			string seg2 = ipv4Address[4..7];
			if (seg2.EndsWith('.') &&
				String.Compare(seg2,"16.") >= 0 &&
				String.Compare(seg2,"31.") <= 0)
			{
				return true;
			}
		}
	}

	return false;
}

注意這種方式在驗證A類網站和C類網站時都非常簡單(確實約大多數客戶都會用這兩種)。B類網路是個特例,讓這個程式碼稍複雜化了,需要多對幾個字串進行判斷——導致程式碼比較複雜。

輸入結果如下:

[ ] Expected: False,Actual: False
[ Not A IP] Expected: False,Actual: False
[ 225.5.5.5] Expected: False,Actual: False
[175.10.74.64] Expected: False,Actual: False
[192.168.1.13] Expected: True,Actual: True
[10.10.24.220] Expected: True,Actual: True
[172.24.1.120] Expected: True,Actual: True
[172.32.1.120] Expected: False,Actual: False

我覺得這種方法……還挺不錯,關鍵都是很直白的API呼叫,淺顯易懂,如果我是技術負責人,我多半是允許員工寫這種方式的。

另外如果追求“函式式”,可能可以寫成這個樣子,實現“一行程式碼”搞定(效果一樣):

bool IsPrivateNetwork2(string ipv4Address) => IPAddress.TryParse(ipv4Address,out _) && (
	ipv4Address.StartsWith("192.168.") ||
	ipv4Address.StartsWith("10.") ||
	ipv4Address.StartsWith("172.") && ipv4Address[6] == '.' && int.Parse(ipv4Address[4..6]) switch
	{
		var x when x >= 16 && x <= 31 => true,_ => false
	}
);

方法2——使用IPAddress

.NET是個寶庫,除了可以使用IPAddress類輔助做驗證,實現起來會簡單許多:

bool IsPrivateNetwork3(string ipv4Address)
{
	if (IPAddress.TryParse(ipv4Address,out var ip))
	{
		byte[] ipBytes = ip.GetAddressBytes();
		if (ipBytes[0] == 10) return true;
		if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31) return true;
		if (ipBytes[0] == 192 && ipBytes[1] == 168) return true;
	}

	return false;
}

該方式的關鍵是藉助IPAddress類的GetAddressBytes()方法,即可非常輕鬆地完全這個驗證——同時代碼更簡單。

如果追求“函式式”程式設計,“一行”程式碼的版本如下(效果相同):

bool IsPrivateNetwork(string ipv4Address) => IPAddress.TryParse(ipv4Address,out var ip) && ip.GetAddressBytes() switch 
{
	var x when x[0] == 10 => true,var x when x[0] == 172 && x[1] >= 16 && x[1] <= 31 => true,var x when x[0] == 192 && x[1] == 168 => true,_ => false
};

方法3——使用正則表示式

這種挺麻煩的,但也沒什麼好說的,直接上程式碼:

bool IsPrivateNetwork(string ipv4Address) => Regex.IsMatch(input,@"(^192\.168\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)|(^172\.([1][6-9]|[2][0-9]|[3][0-1])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)|(^10\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)",RegexOptions.None);

這才是真一行程式碼搞定😂

不開玩笑,正則表示式效能其實差很多,比以上兩種方式差得遠——最關鍵的是,我把這正則表示式寫出來,就再也不想維護了😂

總結

俗話說“條條道路通羅馬”,完成一件簡單的任務可能會存在不同的辦法,但辦法與辦法之間還是有較大的區別,我覺得重點的是要多寫,多比較,多體會。

以上就是如何用C#驗證IP是否為區域網地址的詳細內容,更多關於C#驗證IP是否為區域網的資料請關注我們其它相關文章!