VB.NET 讀取純真IP數據庫

博客剛弄好幾天,黑客比搜索引擎還快找上門來,這讓小白好大壓力。

難道WordPress的安全性已經低得不能再低了麼?真搞不懂他是怎麼找到我的。

從後台日誌裡看到關於這位仁兄的入侵過程,看上去有幾千條記錄,感覺IP地址來來去去也就那麼幾個,估計那位仁兄是拿我的博客練練手的。

各種URL注入就不多說了,不知道他還會不會來,都是中國人,何必為難自己人呢?

既然有IP地址,不如來查下這些IP地址都是哪裡的,看看那位仁兄用哪裡的電腦攻擊的。

經過強大的Excel過濾,幾千條記錄去除重複只剩下幾條記錄,還可以做下數據透視表,分析攻擊頻率和攻擊次數,現在才發現以前學的辦公軟件使用沒有白費,好東西啊。

篩選出來的結果就不貼了,免得被別有用心的人利用。

儘管真正的IP地址也就幾條,但我仍然不願意一條條去查歸屬地,試試搜下Excel能不能做自動查歸屬地的功能,後來發現自己SB了,這都能想到。

但是無獨有偶,被我遇到C#調用純真IP數據庫的示例。這個主意不錯,可以不用網頁,減少對網絡的依賴性。當年珊瑚QQ也是用這個數據庫做大,可謂是紅透半邊天啊,現在珊瑚QQ早已消失,可純真的還在更新,不得不佩服他們的毅力。贊一個。

根據那個示例是調用網上開源的DLL進行讀取數據庫的,使用起來超級簡單,只要設置數據庫文件路徑,然後就可以傳入IP地址進行查詢。

先附上示例代碼的下載鏈接(包含3個版本):地址

原示例代碼:

Stopwatch stopwatch = new Stopwatch();
  List<string> ips = new List<string> { "218.5.3.128", "120.67.217.7", "125.78.67.175", "220.250.64.23", "218.5.3.128", "120.67.217.7", "125.78.67.175", "220.250.64.23" };
  stopwatch.Start();
  for (int i = 0; i < 100; i++)
  {
     foreach (string item in ips)
     {
          ip = qqWry.Query(item);
        // Console.WriteLine("{0} {1} {2}", ip.IP, ip.Country, ip.Local);
    }
 }
  
 stopwatch.Stop();
 Console.WriteLine("QQWryLocator 花了{0} ms", stopwatch.ElapsedMilliseconds);
  
 stopwatch.Reset();
 stopwatch.Start();
 for (int i = 0; i < 100; i++)
 {
    foreach (string item in ips)
    {
        string s = IPLocation.IPLocation.IPLocate("qqwry.dat", item);
       // Console.WriteLine(s);
    }
 }
 stopwatch.Stop();
 Console.WriteLine("IPLocation 花了{0} ms", stopwatch.ElapsedMilliseconds);

原示例截圖:

image_thumb_2


 

原示例已經在IPLocation基礎上進行優化得到了更好的性能,這裡用到的算法非常簡單(第二次面試的時也有過這樣的試題,但想不通怎麼更好地解決單數的問題,人外有人,總有人會想到的)

算法這東西說理論很難說明,我還是舉個例子說吧,就用我面試的那個試題吧。

你有100個蘋果,一個天枰,其中一個蘋果比較輕,要求用最少比較次數找到這個蘋果。

按照一般情況下,肯定是一個個蘋果比較,要經過99次才能找到,明顯不符和要求,而且很慢。

那麼我們可以把這100個蘋果分成兩組,每組50個(當時我想那天枰得有多大)進行比較。(50:50) – 1

找到比較輕的那組,然後將那組再分成兩組25再比較。(25:25) – 2

繼續分的話會遇到單數問題,直接把多出來的拿兩個出來單獨比較找到較輕的那個,放一邊。(1:1) – 3

如此類推

24:24  –  4

12:12  –  5

6:6   –  6

3:3   –   7

1:1   –  8……………這裡比較出來的就要與前邊第三次出來的蘋果進行比較 1:1   –  9

2:2  –  10

1:1   –  11

這樣較輕的蘋果就出來了,然後你就可以去找老闆換一個大的。

原本要比較99次,現在只需要11次就可以找到了,這算是初步感受算法的魅力,的確很強大。

算法講完了,回到程序來。

原示例已經將耗時縮減80%,但有些網友還不滿足,感覺仍然有點慢,繼續優化下。

這裡就出現了新的版本,算法方面沒有改變,改的是算法所用到的一些方法。

比較蘋果還是用原來的方式,但我加快手腳搬動那些蘋果,從而節省大量時間。

原示例代碼即將優化的代碼:

 private long GetStartIp(long left, out long endIpOff)
        {
            long leftOffset = firstStartIpOffset + (left * 7L);
            byte[] buffer = new byte[7];
            Array.Copy(data, leftOffset, buffer, 0, 7);
            endIpOff = (Convert.ToInt64(buffer[4].ToString()) + (Convert.ToInt64(buffer[5].ToString()) * 0x100L)) + ((Convert.ToInt64(buffer[6].ToString()) * 0x100L) * 0x100L);
            return ((Convert.ToInt64(buffer[0].ToString()) + (Convert.ToInt64(buffer[1].ToString()) * 0x100L)) + ((Convert.ToInt64(buffer[2].ToString()) * 0x100L) * 0x100L)) + (((Convert.ToInt64(buffer[3].ToString()) * 0x100L) * 0x100L) * 0x100L);
        }
        private long GetEndIp(long endIpOff, out int countryFlag)
        {
            byte[] buffer = new byte[5];
            Array.Copy(data, endIpOff, buffer, 0, 5);
            countryFlag = buffer[4];
            return ((Convert.ToInt64(buffer[0].ToString()) + (Convert.ToInt64(buffer[1].ToString()) * 0x100L)) + ((Convert.ToInt64(buffer[2].ToString()) * 0x100L) * 0x100L)) + (((Convert.ToInt64(buffer[3].ToString()) * 0x100L) * 0x100L) * 0x100L);
        }

代碼裡有很多這種“0x100L”的地方,而這兩個方法又是100%用在算法上。這裡的相乘屬於操縱數據起始位置和結束位置,具體要到什麼位置就要看數據是什麼的格式了。

使用Convert.ToInt64把性能拖了一大截,還加上了乘法,效率再次下降,如果將Convert.ToInt64改為強制轉換,乘法改為移位,那麼性能將會提升到新的台階。

優化後代碼

 private uint GetStartIp(uint left, out uint endIpOff)
        {
            int leftOffset = (int)(firstStartIpOffset + (left * 7));
            endIpOff = (uint)data[4 + leftOffset] + (((uint)data[5 + leftOffset]) << 8) + (((uint)data[6 + leftOffset]) << 16);
            return (uint)data[leftOffset] + (((uint)data[1 + leftOffset]) << 8) + (((uint)data[2 + leftOffset]) << 16) + (((uint)data[3 + leftOffset]) << 24);
        }

        private uint GetEndIp(uint endIpOff, out int countryFlag)
        {
            countryFlag = data[4 + endIpOff];
            return (uint)data[endIpOff] + (((uint)data[1 + endIpOff]) << 8) + (((uint)data[2 + endIpOff]) << 16) + (((uint)data[3 + endIpOff]) << 24);
        }

原示例代碼中還有很多地方用乘法的地方,優化都是改成上面的方法,就不多說了。

3個版本執行速度比較,2.0版完爆之前的兩個版本。

图像 001

OK,理解地差不多了,就要動手我目的,批量查詢IP地址歸屬地。很久沒用VB.NET,就把C#轉換成VB.NET吧,以免忘記不會寫VB了。

轉過來後,會出現C#的強制轉換Long轉Integer到VB.NET下不能正常運行,關於這個明天再說,要睡了。

附上轉換好了的VB.NET代碼:純真數據庫應用

編寫環境VS2012     .NET4

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注