受 UTF-8中文字符切割时 pack/unpack的启发,看了下其 man 文档,发现这两个函数的功能如此之强大,下面就 IP地址或子网掩码的二进制和十进制之间的转换为例,让我们感受下吧
IP 地址: 192.168.2.1
子网掩码:255.255.255.128
CIDIR 表示: /25
#### 将十进制数转换成8为二进制
sub dectobin {
substr(unpack("B32",pack("N",shift)) , -8);
}
#### 将32位二进制转换成十进制
sub bintodec {
unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}
#### 将二进制表示的 IP/子网掩码转换成十进制形式
sub ipmask_bin2dec {
my $prefix = "";
my $result;
map { $result .= $prefix . &bintodec($_); $prefix = ".";
} split (/\./,shift);
return $result;
}
#### 将十进制表示的 IP/子网掩码转换成二进制形式
sub ipmask_dec2bin {
my $prefix = "";
my $result;
map { $result .= $prefix . &dectobin($_); $prefix = ".";
} split (/\./,shift);
return $result;
}
#### 将 CIDR 表示的子网掩码转换成十进制形式
sub ipmask_cidr2dec {
my $cidr_num = shift();
return if ($cidr_num < 0 || $cidr_num > 32);
(my $mask = 1 x $cidr_num . 0 x (32-$cidr_num)) =~
s/(\d{8})(\d{8})(\d{8})(\d{8})/\1.\2.\3.\4/;
return &ipmask_bin2dec($mask);
}
my $dec_ip = "192.168.2.1";
my $dec_mask = "255.255.255.128";
my $cidr_num = 25;
my $bin_ip = &ipmask_dec2bin($dec_ip);
my $bin_mask = &ipmask_dec2bin($dec_mask);
my $bin_mask2 = &mask_cidr2dec($cidr_num);
print "Decimal IP: $dec_ip\n";
print "Binary IP: $bin_ip\n";
print "Decimal Netmask: $dec_mask\n";
print "Binary Netmask: $bin_mask\n";
print "CIDR Netmask: $cidr_num = $bin_mask2\n";
输出:
Decimal IP: 192.168.2.1
Binary IP: 11000000.10101000.00000010.00000001
Decimal Netmask: 255.255.255.128
Binary Netmask: 11111111.11111111.11111111.10000000
CIDR Netmask: 25 = 255.255.255.128
附:完善后的程序(ipmask.pl)
#!/usr/bin/perl
#**********************************************************
# Description : IP/Netmask/Network presentation format
# Author : Muddyboot - toobyddum@gmail.com
# Last modified : 2007/01/21
#**********************************************************
use strict;
#### Convert decimal number to 8-octs binary format
#### eg: 12 -> 00001100
sub dec2bin {
substr(unpack("B32",pack("N",shift)) , -8);
}
#### Convert binary number to decimal format
#### eg: 1100 -> 12
sub bin2dec {
### prefix-padding 32 zeros , then pick the last 32 octs
unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}
##### Convert IP/Mask from binary to decimal format
#### eg: 11000000.10101000.00000010.00000001 -> 192.168.2.1
sub ipmask_bin2dec {
my $prefix = "";
my $result;
map { $result .= $prefix . &bin2dec($_); $prefix = ".";
} split (/\./,shift);
return $result;
}
#### Convert IP/Mask from decimal to binary format
#### eg: 192.168.2.1 -> 11000000.10101000.00000010.00000001
sub ipmask_dec2bin {
my $prefix = "";
my $result;
map { $result .= $prefix . &dec2bin($_); $prefix = ".";
} split (/\./,shift);
return $result;
}
#### Convert Mask from CDIR number to decimal format
#### eg: 25 -> 255.255.255.128
sub mask_cidr2dec {
my $cidr_num = shift();
return if ($cidr_num < 0 || $cidr_num > 32);
(my $mask = 1 x $cidr_num . 0 x (32-$cidr_num)) =~
s/(\d{8})(\d{8})(\d{8})(\d{8})/\1.\2.\3.\4/;
return &ipmask_bin2dec($mask);
}
#### Convert Mask from CDIR number to decimal format
#### eg: 25 -> 255.255.255.128
sub mask_dec2cidr {
my $decmask = shift();
(my $binmask = &ipmask_dec2bin($decmask)) =~ s/(\.|0)//g;
return length($binmask);
## Another way
## (my $binmask = &ipmask_dec2bin($decmask)) =~ s/\.//g;
## return rindex($binmask,1) + 1;
}
#### Valid IP address format, return nothing if is OK
sub validIP () {
my $ip = shift();
return 1 if ($ip !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
my @octs = split(/\./,$ip);
return 1 if (scalar(@octs) != 4);
map {
return 1 if ($_ > 256);
} @octs;
return;
}
#### Valid Netmask address format, return nothing if is OK
sub validMask () {
my $mask = shift();
return 1 if ($mask !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
### remove serial 0 part, then judge if the remain string contain 0
(my $bin_mask = &ipmask_dec2bin($mask)) =~ s/\.//g;
$bin_mask =~ s/0*$//;
return 1 if ($bin_mask =~ /0/);
return;
}
die "Usage: ipmask.pl [netmask]\n" if (scalar(@ARGV) < 1);
my $dec_ip = shift();
my $dec_mask = shift();
$dec_mask = "255.255.255.0" if (! $dec_mask);
die "Bad IP Address format: $dec_ip\n" if (&validIP($dec_ip));
die "Bad Netmask format: $dec_mask\n" if (&validMask($dec_mask));
my $bin_ip = &ipmask_dec2bin($dec_ip);
my $bin_mask = &ipmask_dec2bin($dec_mask);
my $cidr_mask = &mask_dec2cidr($dec_mask);
(my $bin_wildcard = $bin_mask) =~ tr/[01]/[10]/;
my $dec_wildcard = &ipmask_bin2dec($bin_wildcard);
#### cut the 1 part of wildcard, then calc its decimal value
(my $tmp = $bin_wildcard) =~ s/(\.|0)//g;
my $wild_count = &bin2dec($tmp);
my $host_count = ($wild_count == 0) ? 1 : (($wild_count == 1) ? 2 : $wild_count -1 );
my ($bin_network,$dec_network,$dec_broadcast,$max_host,$min_host);
if ($host_count > 1) {
$bin_network = $bin_ip & $bin_mask;
$dec_network = &ipmask_bin2dec($bin_network);
if ($wild_count > 2) {
#### bit-or operation on wildcard and network
$dec_broadcast = &ipmask_bin2dec($bin_wildcard | $bin_network);
}
#### bit-or operation on wildcard and network, then set the last bit to 0
$max_host = &ipmask_bin2dec( ($bin_wildcard | $bin_network) &
(1 x 8 . "." . 1 x 8 . "." . 1 x 8 . "." . 1 x 7 . 0));
$min_host = &ipmask_bin2dec($bin_network |
(0 x 8 . "." . 0 x 8 . "." . 0 x 8 . "." . 0 x 7 . 1));
}
my $maxlen = 20;
printf "%-${maxlen}s%s\n", "Decimal IP:", $dec_ip;
printf "%-${maxlen}s%s\n", "Binary IP:", $bin_ip;
printf "%-${maxlen}s%s\n", "Decimal Netmask:", $dec_mask;
printf "%-${maxlen}s%s\n", "Binary Netmask:" , $bin_mask;
printf "%-${maxlen}s%s\n", "Decimal Wild Card:", $dec_wildcard;
printf "%-${maxlen}s%s\n", "Binary Wild Card:", $bin_wildcard;
if ($host_count > 1) {
printf "%-${maxlen}s%s\n", "Network:", $dec_network . "/$cidr_mask" ;
($wild_count > 2) && printf "%-${maxlen}s%s\n", "Broadcast:", $dec_broadcast;
printf "%-${maxlen}s%s\n", "Max Host:", $max_host;
printf "%-${maxlen}s%s\n", "Min Host:", $min_host;
}
printf "%-${maxlen}s%s\n", "Hosts Count:", $host_count;
|
晕,Perl 代码用套用代码样式后,注释的颜色看起来好不舒服(刺眼+不清楚)
阅读(1932) | 评论(0) | 转发(0) |