Chinaunix首页 | 论坛 | 博客
  • 博客访问: 596916
  • 博文数量: 40
  • 博客积分: 7274
  • 博客等级: 少将
  • 技术积分: 410
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-20 15:00
个人简介

Expired

文章分类
文章存档

2011年(1)

2008年(3)

2007年(17)

2006年(10)

2005年(9)

分类:

2007-01-21 11:58:41

受 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) |
给主人留下些什么吧!~~