鉴于IPv4地址(针)和未分类的IPv4地址数组(haystack),我怎样才能以编程方式确定给定大海捞针中哪个单个地址最接近(网络方式,非地理位置)?
由于我无法访问每个地址的网络掩码,因此解决方案应该忽略netmasks和traceroute等选项。
使用各种地址,我的意思是:私人,保留,广播,局域网和广域。
欢迎以理论,伪代码,python,php或perl形式提供任何帮助。
问题Getting IP address list between two IP addresses大致相似,但它确实削减了它。
答案 0 :(得分:1)
我仍然不太确定你在问什么,但根据你的评论
我最近的意思是@PeterGibson,192.168.1.101更接近 192.168.56.1而不是172.30.130.66。并且192.168.1.254更接近192.168.1.240而不是192.168.2.1
您可以尝试以下python代码来执行距离函数:
import socket
def dist(a, b):
def to_num(addr):
# parse the address string into integer quads
quads = map(ord, socket.inet_aton(addr))
# spread the quads out
return reduce(lambda x,y: x * 0x10000 + y, quads)
return abs(to_num(a) - to_num(b))
返回的数字相当随意,但应足以满足基本需求。我仍然不确定它应该如何处理广播地址等。
一些例子:
>>> dist('192.168.1.254', '192.168.1.240')
14L
>>> dist('192.168.1.254', '192.168.2.1')
65283L
>>> dist('192.168.1.101', '192.168.56.1')
3604380L
>>> dist('192.168.1.101', '172.30.130.66')
5630092231245859L
答案 1 :(得分:0)
我首先将数组划分为组,考虑保留的ip-addresses(http://en.wikipedia.org/wiki/Reserved_IP_addresses#Reserved_IPv4_addresses)。然后我按地区分开。也许一些树形结构就足够了:根节点是顶级区域,然后,它接近叶子,它适用于较小的区域。
答案 2 :(得分:0)
不是最漂亮的方法,但由于不需要非常高的性能,它可以完成这项工作。
<?php
$ip = isset($argv[1]) ? $argv[1] : '192.168.1.254';
printf("Input => %s => %u\n", $ip, ip2long($ip));
var_dump(
net_distance(
$ip,
array(
'87.86.85.84',
'173.194.41.170',
'192.168.1.150',
'192.168.1.245',
'192.168.2.2',
'192.168.56.50',
)
)
);
// The problem assumes that:
// a) any local (127) and lan (10,172,192) IPs are closer to each other than to any wan IP.
// b) any wan IP is closer to local and lan IPs than to other wan IP.
function net_distance($src_ip, $list)
{
if (in_array($src_ip, $list)) {
return $src_ip; // exact match
}
list($a0, $b0, $c0, $d0) = explode('.', $src_ip, 4);
$triples = array();
$doubles = array();
$singles = array();
foreach($list as $ip) {
list($a1, $b1, $c1, $d1) = explode('.', $ip, 4);
if ($a0 == $a1 && $b0 == $b1 && $c0 == $c1) { // match A.B.C.x
$triples[] = $ip;
}
elseif ($a0 == $a1 && $b0 == $b1) { // match A.B.x.y
$doubles[] = $ip;
}
elseif ($a0 == $a1 || (in_array($a0, array(127, 10, 172, 192)) && in_array($a1, array(127, 10, 172, 192)))) {
$singles[] = $ip; // match A.x.y.z or both As are *likely* to be lan addresses
}
}
if (count($triples) > 0) {
$list = $triples;
}
elseif (count($doubles) > 0) {
$list = $doubles;
}
elseif (count($singles) > 0) {
$list = $singles;
}
$min = PHP_INT_MAX;
$rtn = false;
$l1 = ip2long($src_ip);
foreach($list as $ip)
{
$l2 = ip2long($ip);
$d = ($l1 > $l2) ? $l1 - $l2 : $l2 - $l1;
// echo "\t" . str_pad($ip, 15, ' ', STR_PAD_RIGHT) . " => $l2 => $d\n";
if ($min > $d) {
$rtn = $ip;
$min = $d;
}
}
return $rtn;
}