[转帖]Perl扩展实战 ------ 获得ip的来源地址

Perl扩展实战 ------ 获得ip的来源地址1 前言 2 Perl扩展 2.1 什么是Perl的扩展? 2.2 一些扩展的例子 2.3 两种Per扩展方法 2.4 用 h2xs 制作Perl扩展 2.5 实例说明 3 测试扩展 3.1 安装扩展 3.2 测试效率 4 小结1 前言 写这篇文章之前,听一些大牛们说,现在Perl是国内最不值钱的技术,不能给自身带来切身的利益,一般都是PHP+Mysql+Web2.0能带来丰厚的收入,因为国内需要这样的人;且不说Perl为什么不值钱,毕竟用Perl多年,无论从Web还是脚本还是GUI界面的编程,笔者觉得Perl功能强大却在国内如此衰弱,於心不忍。Perl能做很多事情,减少大量重复代码的开发,但是效率并不一定高效,甚至比起后起之秀python都有所不及,但perl 是自由免费的。 2 Perl扩展 2.1 什么是Perl的扩展? 可以简单认为非内置模块都属于Perl的扩展模块,Perl的扩展是指在本身基础上进行的一些功能改进。在 cpan 网站有各种各样的丰富模块扩展。 根据模块相关的定义,有些模块纯粹是在Perl的基础上扩展的;就跟盖房子似的,房子盖得越高,虽然住得人越来越多,但是后来人到达楼顶的时间也越来越多。 扩展可以基于 C/C++ 甚至汇编语言,程序编译成二进制后,调用其 api 函数,就好比房子上按上了一部直达楼顶电梯,这种感觉在你理解这篇文章后就会感觉得到。 2.2 一些扩展的例子 起先,对Web用图多的或者做过一些监测的人都应该知道鼎鼎有名的 ChartDirector ,这个是一个商业绘图软件,优秀的软件性能以及漂亮的图形让人惊叹不已;下载试用版,可以看到这些软件都是经过编译成二进制后,调用其中 api 函数运行; 使用过php的人应该知道 Zend软件 ,其实 Zend Optimizer 软件就是针对PHP的一个扩展,使用 Zend Guard 或 Zend Studio 将php程序压缩成二进制文件,然后使用 Zend Optimizer 来解读该二进制文件,这样不仅效率高,而且带宽、所耗资源都非常低。 2.3 两种Per扩展方法 目前笔者所知道有两种方法写Perl扩展,一种是 h2xs ,另外一种是 Inline::C ,以 Inline::C 为例: [code]package MyWrapper;
use Inline => Config => LIBS => '-L/usr/local/mylib -lmylib';
use Inline => Config => INC  => '-I/usr/local/mylib';
use Inline C;
sub version {
   return "MyWrapper 2.0";
}
__DATA__
__C__
#include "mylib.h"
   
SV* new() {
    void * session = newsession();
    SV*    obj_ref = newSViv(0);
    SV*    obj = newSVrv(obj_ref, class);
    sv_setiv(obj, (IV)session);
    SvREADONLY_on(obj);
    return obj_ref;
}
   
void set (SV* obj, char *attribute, char *value) {
    setattribute ( ((void*)SvIV(SvRV(obj))), attribute, value);
}
   
char* get (SV* obj) {
    return getresult ( ((void *)SvIV(SvRV(obj))) );
}
   
void DESTROY(SV* obj) {
    return freesession ( ((void *)SvIV(SvRV(obj))) );
}

[/code]Inline::C 模块让人感觉代码利用率比较低,需要许多代码的重写和转换,不推荐使用,这里主要还是介绍 h2xs 工具。 2.4 用 h2xs 制作Perl扩展 首先确保机器安装perl5.6以上版本(因为这个版本才会有h2xs及load工具); 接着使用 h2xs 这个工具来生成一个目录,目录中是一些扩展模块模板; 根据自己的需求用Perl、C/C++或者汇编等语言写一些功能扩展; 然后根据自己的需求编辑 Makefile.PL 、 module.xs 和 lib/module.pm 文件,完成Perl的扩展。 2.5 实例说明 运行 h2xs 命令,生成一个 getaddress 目录: h2xs -O -n getaddress进入该目录: [code]$cd getaddress
$ll
total 64
drwxr-xr-x  2 lijunlia users  4096 Feb  1 16:08 t
-rw-r--r--  1 lijunlia users  1173 Feb  1 16:08 README
-rw-r--r--  1 lijunlia users 29773 Feb  1 16:08 ppport.h
-rw-r--r--  1 lijunlia users   135 Feb  1 16:08 MANIFEST
-rw-r--r--  1 lijunlia users  1780 Feb  1 16:08 Makefile.PL
drwxr-xr-x  2 lijunlia users  4096 Feb  1 16:08 lib
-rw-r--r--  1 lijunlia users   169 Feb  1 16:08 getaddress.xs
drwxr-xr-x  2 lijunlia users  4096 Feb  1 16:08 fallback
-rw-r--r--  1 lijunlia users   155 Feb  1 16:08 Changes[/code]将写好的 QQWry.h 和 QQWry.c 放置该目录,QQWry.h 和 QQWry.c 文件是计算 QQWry.dat 数据的程序,相关参考文档见 纯真IP数据库格式详解; 接着编辑 Makefile.PL 文件,内容如下: [code]use 5.008005;
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
    NAME              => 'getaddress',
    VERSION_FROM      => 'lib/getaddress.pm', # finds $VERSION
    PREREQ_PM         => {}, # e.g., Module::Name => 1.1
    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
      (ABSTRACT_FROM  => 'lib/getaddress.pm', # retrieve abstract from module
       AUTHOR         => 'Junliang Li <lijunlia@localdomain>') : ()),
    LIBS              => [''], # e.g., '-lm'
    DEFINE            => '', # e.g., '-DHAVE_SOMETHING'
    INC               => '-I.', # e.g., '-I. -I/usr/include/other'
        # Un-comment this if you add C files to link with later:
    # OBJECT            => '$(O_FILES)', # link all the C files too
);
if  (eval {require ExtUtils::Constant; 1}) {
  # If you edit these definitions to change the constants used by this module,
  # you will need to use the generated const-c.inc and const-xs.inc
  # files to replace their "fallback" counterparts before distributing your
  # changes.
  my @names = (qw());
  ExtUtils::Constant::WriteConstants(
                                     NAME         => 'getaddress',
                                     NAMES        => \@names,
                                     DEFAULT_TYPE => 'IV',
                                     C_FILE       => 'const-c.inc',
                                     XS_FILE      => 'const-xs.inc',
                                  );

}
else {
  use File::Copy;
  use File::Spec;
  foreach my $file ('const-c.inc', 'const-xs.inc') {
    my $fallback = File::Spec->catfile('fallback', $file);
    copy ($fallback, $file) or die "Can't copy $fallback to $file: $!";
  }
}[/code] 为了构造出 Makefile 文件,所有的设置在 WriteMakefile? 这个函数里面,其中 c link file 添加: OBJECT                    => 'getaddress.o QQWry.o',修改 getaddress.xs 文件,如下: [code]#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "QQWry.h"
#include "ppport.h"

#include "const-c.inc"

MODULE = getaddress             PACKAGE = getaddress

INCLUDE: const-xs.inc

PROTOTYPES: DISABLE

char* getipwhere (char *filename, char *ip)
        CODE:
        {
                RETVAL = getipwhere (filename, ip);
        }
        OUTPUT:
                RETVAL

[/code] 目的是生成两个目标文件:getaddress.o QQWry.o。 lib目录的 getaddress.pm 是模块模板样例;修改 lib/getaddress.pm,若直接调用函数,只需要在 @EXPORT 里面添加其函数名称即可,如果需要使用的是面对对象的方法,模块需要使用面对对象的模块就可以了,加入函数: [code]# Preloaded methods go here.
sub ipwhere
{
    my $ip = shift;
    my $ipfile = shift;
    $ipfile = "data/QQWry.Dat" unless ($ipfile);
    my $ipaddr = getipwhere ($ipfile, $ip);
    return '未知地区' unless ($ipaddr);
    $ipaddr =~ s/CZ88\.NET//ig;
    $ipaddr =~ s/^\s*//;
    $ipaddr =~ s/\s*$//;
    $ipaddr = '未知地区' if (!$ipaddr || $ipaddr =~ /未知|http/i);
    return $ipaddr;
}[/code] 需要注意的是,若不想使用 AutoLoader? 模块加载动态链接库,可以使用 require DynaLoader;bootstrap testinfo;加载动态链接库, 完整包如下: getaddress.tar.bz2 getaddress.tar.gz 3 测试扩展 3.1 安装扩展 安装扩展非常简单: perl Makefile.PLmakemake install值得注意的是,安装需要root权限; 3.2 测试效率 拿两个例子比较一下,一个是纯Perl写的脚本、一个是使用C语言扩展的脚本,其耗费时间如下表格: 指标  Perl  扩展  描述  消耗时间  3.739043  0.111362  600次查询的打印结果  其脚本例子已在完整包里面说明。 4 小结 通过上述实例,可以看到使用二进制的编译比普通查询快的多,若要多次进行查询,这个扩展就不合适了,因为磁盘读写最多,最好的办法还是直接读入放到内存,这样会更快一些; 由此看来,perl也可以通过一些二进制的编译实现一些高效率的功能,并且让过程变得更加简单; 此扩展在Windiws以及Linux下编译通过。 来源:[url]http://my.huhoo.net/archives/2008/02/perl_ip.html[/url]

[[i] 本帖最后由 Ecore 于 2008-3-14 11:52 编辑 [/i]]