C#验证IP是否为局域网地址的三种方法
C#驗(yàn)證IP是否為局域網(wǎng)地址的三種方法
前一陣子有【廣州.NET群】的客戶問起這個問題,說他們需要驗(yàn)證客戶輸入的網(wǎng)站是否為局域網(wǎng)。其實(shí)局域網(wǎng)的?IP并沒有確定的定義,只要是局域網(wǎng)中,即可設(shè)置為任何一個?IP。
但確實(shí)存在一個?內(nèi)網(wǎng)保留地址的定義,它會確保公網(wǎng)?IPv4的地址不會分配在“?內(nèi)網(wǎng)保留地址”中,該地址定義如下:
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。
客戶澄清,他確實(shí)就是想驗(yàn)證?IPv4字符串是否為?內(nèi)網(wǎng)保留地址。
下面我們來想想幾種驗(yàn)證?IPv4地址字符串是否為?內(nèi)網(wǎng)保留地址的方法。
首先寫出該方法的簽名:
bool IsPrivateNetwork(string ipv4Address) { }然后構(gòu)建測試數(shù)據(jù),顯示期待結(jié)果:
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等方式來實(shí)現(xiàn):
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; }注意這種方式在驗(yàn)證?A類網(wǎng)站和?C類網(wǎng)站時都非常簡單(確實(shí)約大多數(shù)客戶都會用這兩種)。?B類網(wǎng)絡(luò)是個特例,讓這個代碼稍復(fù)雜化了,需要多對幾個字符串進(jìn)行判斷——導(dǎo)致代碼比較復(fù)雜。
輸入結(jié)果如下:
[ ] 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我覺得這種方法……還挺不錯,關(guān)鍵都是很直白的?API調(diào)用,淺顯易懂,如果我是技術(shù)負(fù)責(zé)人,我多半是允許員工寫這種方式的。
另外如果追求“函數(shù)式”,可能可以寫成這個樣子,實(shí)現(xiàn)“一行代碼”搞定(效果一樣):
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類輔助做驗(yàn)證,實(shí)現(xiàn)起來會簡單許多:
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; }該方式的關(guān)鍵是借助?IPAddress類的?GetAddressBytes()方法,即可非常輕松地完全這個驗(yàn)證——同時代碼更簡單。
如果追求“函數(shù)式”編程,“一行”代碼的版本如下(效果相同):
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——使用?正則表達(dá)式
這種挺麻煩的,但也沒什么好說的,直接上代碼:
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);這才是真一行代碼搞定????
不開玩笑,正則表達(dá)式性能其實(shí)差很多,比以上兩種方式差得遠(yuǎn)——最關(guān)鍵的是,我把這正則表達(dá)式寫出來,就再也不想維護(hù)了????
總結(jié)
俗話說“條條道路通羅馬”,完成一件簡單的任務(wù)可能會存在不同的辦法,但辦法與辦法之間還是有較大的區(qū)別,我覺得重點(diǎn)的是要多寫,多比較,多體會。
喜歡的朋友請關(guān)注我的微信公眾號:【DotNet騷操作】
總結(jié)
以上是生活随笔為你收集整理的C#验证IP是否为局域网地址的三种方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在远程 CSM 课程中体验线上工作坊
- 下一篇: c# char unsigned_dll