我使用yii2。我需要通过方法getFreeIPAddress找到未使用的IP(不在数据库中)。我有这样的课:
class Radreply extends ActiveRecord {
const ATTRIBUTE_DEFAULT_IP_ADDRESS = 'Framed-IP-Address';
const IP_ADDRESS_MAX = '10.255.255.255'; // max value for IP
const IP_ADDRESS_MIN = '10.0.0.11'; // min value for IP
public function getIntegerIP(){ // converts IP from string to integer format
return ip2long($this->value);
}
public static function getFreeIPAddress(){
$records = self::findAll(['attribute'=>self::ATTRIBUTE_DEFAULT_IP_ADDRESS]); // get all record which contain IP address
$existIPs = ArrayHelper::getColumn($records,'integerIP'); // get array of IP which is converted to integer by method getIntegerIP
for ($integerIP = ip2long(self::IP_ADDRESS_MIN); $integerIP<=ip2long(self::IP_ADDRESS_MAX); $integerIP++){
// increasing one by one IP address in integer format from value IP_ADDRESS_MIN to value IP_ADDRESS_MAX
if (!in_array($integerIP, $existIPs)){
$stringIP = long2ip($integerIP);
$arrayDigits = explode('.', $stringIP);
$lastDigit = array_pop($arrayDigits);
if ($lastDigit!='0'){ // check if last digit of IP is not 0
return $stringIP;
}
}
}
return '';
}
}
方法getFreeIPAddress工作find,但是在db中有很多带IP的记录并逐个增加IP并检查db中是否存在这个IP是非常漫长的。我如何优化此算法?是否有更快的方式来获取未使用的IP?
答案 0 :(得分:1)
我想,我已经找到了更好的解决方案而没有数据库中的额外表格
class Radreply extends ActiveRecord {
const ATTRIBUTE_DEFAULT_IP_ADDRESS = 'Framed-IP-Address';
const IP_ADDRESS_MAX = '10.255.255.255'; // max value for IP
const IP_ADDRESS_MIN = '10.0.0.11'; // min value for IP
public function getIntegerIP(){ // converts IP from string to integer format
return ip2long($this->value);
}
public static function getFreeIPAddress(){
$records = self::findAll(['attribute'=>self::ATTRIBUTE_DEFAULT_IP_ADDRESS]); // gets all record which contain IP address
$existIPs = ArrayHelper::getColumn($records,'integerIP'); // gets array of IP which is converted to integer by method getIntegerIP
$intIpAddressMin = ip2long(self::IP_ADDRESS_MIN); // gets min IP in integer format
$endRange = empty($existIPs) ? $intIpAddressMin : max($existIPs); // checks if at least one IP is used
$availableIPs = range( $intIpAddressMin, $endRange + 2); // generates array with available IP addresses (+2 because next address can be with last digit 0)
$missingIPs = array_diff($availableIPs,$existIPs); // removes all used IP
foreach ($missingIPs as $value){
$lastDigit = $value % 256;
if ($lastDigit != 0){
return long2ip($value);
}
}
return '';
}
}
答案 1 :(得分:0)
bool in_array(混合$ needle,数组$ haystack [,bool $ strict = FALSE])
在我看来,你可以设置严格的真实。
我的php代码 strict = false
xhr.addEventListener('error', (err: Event) => {
时间php test.php
<?php
$y="1800";
$x = array();
for($j=0;$j<50000;$j++){
$x[]= "{$j}";
}
for($i=0;$i<30000;$i++){
if(in_array($y,$x)){
continue;
}
}
当strict为 true
时real 0m4.418s
user 0m4.404s
sys 0m0.012s
时间php test.php
for($i=0;$i<30000;$i++){
if(in_array($y,$x ,true)){
continue;
}
}
更重要的是,如果你能按升序获得使用过的ip。你可以得到 o(m + n)时间复杂度,m是你应该尝试的所有ip的长度,n是db中所有ip的长度,合并算法。
如果您可以按升序获取已使用的IP
Pseudocode中的。
real 0m1.548s
user 0m1.540s
sys 0m0.004s
这是我的PHP代码,其中我通过$ count ++重新生成echo ip; 在此演示中,大约有80000个ip,类型为
tmpIp = minIp;
while(temIp <= maxIp){
if( dbIsEmpty){
break;
}
dbIp =getNextFromDb();
while(temIp < dbIp){
printf temIp ;
temIp ++;
}
temIp ++;
}
while(temIp <= maxIp){
printf temIp ;
temIp++;
}
这需要大约10秒;
时间php test.php
184460881
真正的0m10.626s
用户0m10.416s
sys 0m0.168s