2015-07-10 71 views
1

我在node.js中工作,我想要做的事,如下面的僞代碼...執行簡單IP地址比較的最高性能方法是什麼?

let ip_range = [50.1.100.1, 51.1.30.1]; // Converted from a CIDR string. 

let ip_address = 50.2.200.2; // Input IP address. 

if(ip_address >= ip_range[0] && ip_address <= ip_range[1]) 
    block(ip_address); 

上做到這一點的最快方法的任何想法?

我已經檢出了cidr-js,它提供了CIDR轉換功能,但不提供IP地址比較功能。看起來像node-ip可能是一個不錯的選擇。

謝謝!

+1

你爲什麼從CIDR轉換了嗎? CIDR是位掩碼,允許您比較前N位,這與您將獲得的效率大致相同。 – ssube

+0

當然。其實我已經想了一下。 CIDR作爲字符串輸入。這是一個掩碼的問題,或者我應該只是轉換爲數字? –

+1

假設你只是處理IPv4地址,只需將地址轉換爲32位整數並進行比較。 –

回答

3

IP地址,因爲我們知道他們是簡單的32位數字值的字符串表示。

通過轉換字符串表示回其數字值,變得十分容易的範圍內使用本機數字比較地址的內檢查成員,如在下面的代碼:

var atoi = function atoi(addr) { 
    var parts = addr.split('.').map(function(str) { 
    return parseInt(str); 
    }); 

    return (parts[0] ? parts[0] << 24 : 0) + 
     (parts[1] ? parts[1] << 16 : 0) + 
     (parts[2] ? parts[2] << 8 : 0) + 
      parts[3]; 
}; 

var checkIpaddrInRange = function checkIpaddrInRange(ipaddr, start, end) { 
    var num = atoi(ipaddr); 
    return (num >= atoi(start)) && (num <= atoi(end)); 
} 


checkIpaddrInRange('10.0.1.1', '10.0.0.1', '10.0.2.1'); // => true 

checkIpaddrInRange('10.0.3.1', '10.0.0.1', '10.0.2.1'); // => false 

參見fiddle

下面是同樣的事情,完全註釋和正確的錯誤檢查:

/** 
* Checks if ipaddr is valid. 
* @property {string} ipaddr 
* @throws Error 
*/ 
var assertIsIpaddr = function assertIsIpaddr(ipaddr) { 

    if('string' !== typeof ipaddr && ipaddr) { 
    throw new Error('ipaddr must be a non-empty string'); 
    } 

    var parts=ipaddr.split(/\./); 

    if(parts.length !== 4){ 
    throw new Error('ipaddr must have four octets'); 
    } 

    var i=0; 
    parts.map(function(str){ 
     var val=parseInt(str), 
      octet = 4 - i++;; 
     if(val < 0 || val > 255){ 
     throw new Error('octet '+octet+' must be between 0 and 255'); 
     } 
    }); 
}; 

/** 
* Converts an ipaddr to a 32bit integer value. 
* @property {string} addr - the ipaddr to convert 
* @returns {number} 
*/ 
var atoi = function atoi(addr) { 

    // test for validity - will throw! 
    assertIsIpaddr(addr); 

    // convert octets to numbers 
    var parts = addr.split('.').map(function(str) { 
    return parseInt(str); 
    }); 

    // construct result 
    var result = (parts[0] ? parts[0] << 24 : 0) + // if > 0, shift 4th octet left by 24 
       (parts[1] ? parts[1] << 16 : 0) + // if > 0, shift 3rd octet left by 16 
       (parts[2] ? parts[2] << 8 : 0) + // if > 0, shift 2nd octet left by 8 
       parts[3]; 

    // note that if all octets are 255, result will overflow 
    // JavaScript (32bit) number to become -1, so we have to 
    // special case it. I think throwing an error here is a 
    // reasonable solution, since 255.255.255.255 is actually 
    // a broadcast addr. 

    if(result < 0) { 
    throw new Error('255.255.255.255 is not a legal host ipaddr'); 
    } 

    return result; 
}; 

/** 
* Checks ipaddr membership within a range of ipaddrs. 
* @property {string} ipaddr - ipaddr to check 
* @property {string} start - the start of the ipaddr range 
* @property {string} end - the end of the ipaddr range 
* @returns {boolean} - true if ipaddr is between start and end (inclusive) 
*/ 
var checkIpaddrInRange = function checkIpaddrInRange(ipaddr, start, end) { 
    var num = atoi(ipaddr); 
    return (num >= atoi(start)) && (num <= atoi(end)); 
} 

// OK, test it out... 

checkIpaddrInRange('10.0.1.1','10.0.0.1','10.0.2.1'); // => true 

checkIpaddrInRange('10.0.3.1','10.0.0.1','10.0.2.1'); // => false 
0

這樣做可能有一個更簡單的方法,但以下是我可能會採取的方法。

function pad(n) { 
    return (n.length < 3) ? pad('0' + n) : n; 
} 

// return a number with each part of the IP padded out to 3 digits 
function convert(ip) { 
    return parseInt(ip.split('.').map(function (el) { 
     return pad(el); 
    }).join(''), 10); 
} 

// check the number against the range 
function check(range, ip) { 
    ip = convert(ip); 
    return ip >= range[0] && ip <= range[1]; 
} 

// convert the range 
var range = ['50.1.100.1', '51.1.30.1'].map(function (el) { 
    return convert(el); 
}); 

check(range, '51.1.20.2'); // true 
check(range, '51.1.40.2'); // false 

DEMO

相關問題