2008-10-02 103 views
12

對於我的服務器應用程序,我需要檢查一個IP地址是否在我們的黑名單中。你會如何比較IP地址?

什麼是比較IP地址最有效的方法?將IP地址轉換爲整數並比較它們是否有效?

+1

是您的黑名單一個文件,加載到內存中,在數據庫中,是什麼? – 2008-10-02 03:29:43

+1

黑名單的位置並不重要。它仍然會被CPU比較。 但是如果你認爲我應該在我的問題中提到這一點,請告訴我爲什麼黑名單的位置很重要。 – MrValdez 2008-10-02 15:17:55

+1

@MrValdez:從磁盤獲取黑名單的時間遠遠超過將所有條目從int轉換爲字符串的時間,反之亦然。 – MSalters 2009-10-28 14:43:38

回答

27

取決於您使用的是哪種語言,但IP地址通常作爲32位無符號整數存儲,至少在網絡層存儲,因此比較速度很快。即使不是這樣,除非你正在設計一個高性能的分組交換應用程序,它不可能是性能瓶頸。避免過早優化 - 爲可測試性和可伸縮性設計程序,如果您遇到性能問題,則可以使用分析器查看瓶頸的位置。

編輯:爲了澄清,IPv4地址存儲爲32位整數,加上網絡掩碼(IP地址比較不需要)。如果您使用的是較新的和目前比較少見的IPv6,那麼地址將會是128位長。

+0

「目前更稀少」或許需要9.5年後的更新? – MichaelChirico 2018-03-08 10:13:30

4

是的我發現爲了高效率,它將是一個很長的時間,當然你必須以整數形式對黑名單IP進行索引。

7

32位整數是要走的路 - 直到你開始處理128位的IPv6地址。

3

使用像PeerGuardian這樣的工具,它禁止在驅動程序級別的傳入TCP/IP連接到黑名單上的IP。非常安全,無需代碼(可以說:非常安全,,因爲無需代碼)。

1

如果您收到的IP地址作爲字符串,相對於一個字符串可能比將其轉換爲整數表示

更有效,但我會簡介兩種解決方案是肯定的,如果在幾毫秒(納秒!)將對此操作起作用;-)

2

您是否存在效率問題?

如果是這樣,那麼通過一切手段發佈代碼(或僞代碼),我們可以在屍體上挑選。

如果沒有,那麼我會建議嘗試一些簡單的像存儲在分類列表中的條目和使用環境的現有Sort()Find()

5

你的意思是如果你應該比較它作爲文本字符串或將int轉換爲int並比較爲int?

這通常不是這種查找的瓶頸。你可以嘗試實現這兩種方法,並查看哪一種運行速度更快。

IP地址查詢的實際問題通常是進行高效的查詢,利用了您處理IP地址而不僅僅是隨機數的事實。要做到這一點,你可以查詢LC trie,也許this article

顯然這應該只有當你的黑名單擁有數萬或數百萬條目時纔會使你感興趣。如果它只有10-20個條目,那麼應該首選線性搜索,事實上更有趣的問題是文本比較與整數比較。

2

整數比較比字符串比較快得多。

如果將整數存儲在排序列表中,則可以比未排序列表更快地找到它們。

3

我已經完成了這一點,我測試了它,使用unsigned int(32位)是最快的 - 我假設你將它與字符串表示進行比較。

另一件可能對你有幫助的事情是在創建表格時,過去我有2個colums:LowIP和HighIP;這樣我就可以用1條記錄條目將整個IP範圍列入黑名單,並通過檢查範圍內的IP來獲得良好的性能。

3

我曾經繼承代碼,其中有人認爲認爲存儲IP地址爲4 int是一個非常好的事情,除了他們花了他們所有的時間轉換/從int的。

將它們作爲字符串保存在數據庫中要簡單得多,它只需要一個索引。你會驚訝地發現sql server可以索引字符串,而不是4列整數。但是這個IP列表並不適用於黑名單。數據庫往返是相當昂貴的。

如果數據庫過度殺傷,將它們存儲在內存中的字典中,但這只是一個猜測,因爲我們不知道需要比較多少。由於大多數hashcode是32位int,IPv4地址是32位,所以IP地址本身可能只是一個好的散列碼。

但正如其他人指出的,最好的選擇可能是減少服務器上的負載併購買專用硬件。也許你最近將黑名單IP保存在內存中,並定期向路由器發佈新的IP。

如果您是試圖在路由器內製作某些軟件的人,那麼您需要查找您的數據結構手冊並創建類似於B樹的內容。

5
static public bool IsEqual(string ToCompare, 
             string CompareAgainst) 
    { 

    return IPAddressToLongBackwards(ToCompare)==IPAddressToLongBackwards(CompareAgainst); 
    } 

static private uint IPAddressToLongBackwards(string IPAddr) 
    { 
    System.Net.IPAddress oIP=System.Net.IPAddress.Parse(IPAddr); 
    byte[] byteIP=oIP.GetAddressBytes(); 


    uint ip=(uint)byteIP[0]<<24; 
    ip+=(uint)byteIP[1]<<16; 
    ip+=(uint)byteIP[2]<<8; 
    ip+=(uint)byteIP[3]; 

    return ip; 
    } 

如果我正確理解你的話,這是比較兩個IP地址的代碼,你想要嗎?您還可以進一步做這樣的事情一樣......

static public bool IsGreater(string ToCompare, 
           string CompareAgainst) 
    { 

    return IPAddressToLongBackwards(ToCompare)> 
     IPAddressToLongBackwards(CompareAgainst); 
    } 

,因爲你得到了地址字節... 如果你喜歡再投我,但請不要投我負