gyn

Win32下的Perl,无用的select,停滞的Tk,结束吧....

IKC初探

What is IKC not KFC

Component的存在使得我们可以将大多数的精力放在业务逻辑上,但我认为这样同时也减低了程序员对代码的信任度。因为对于像IKC这样一个高级的应用,我们很难确切地理解其中的原理。很多时候我们不得不根据文档亦步亦趋,但始终还是存在那么一些难以定位的逻辑上的错误,对于这些错误warnings是不会给出太多有价值的信息的。所以,多大程度上透彻地理解它们将直接影响到程序的可靠性和可扩展性。

这次要说到的就是IKC,即Inter Kernel Communication,它是用于POE核间通信的组件。确切地说,通过它不同的核可以共享使用事件,这对于跨网络的应用是具有一定的吸引力的。至少,我们将节省解析来自客户端指令这个环节,而是直接提供服务器端函数给客户使用。

The call and post in kernel

下面用到的例子来自于《POE Cookbook》中的“Application Servers 2”一例。客户向服务器发送一串数字,服务器将它们相加并返回结果,客户接收到结果再将其打印出来。为了更好地说明内部的运行机理,我适当地增加了一些代码。事实上为了证实对post_respond的猜测,我还另外用POE::Component::IKC::Client写了一个客户端,并且在服务器端对一两个函数做了很大的修改。不过既然得出了结论,就不阐述其中的细节了。

先来说一下服务器端的一些情况,结构我就不说了,因为以前已经说了很多。注意的一点是,在这里POE::Component::IKC::Server是一个单独的session,和处理业务的主session不同,它是用来接受IKC客户端的请求并协商建立连接。在建立该session的过程中,需要为服务器端程序的核心提供一个便于识别的名称,它将成为核间传递事件地址的一部分。至于这个server本身的session的名称,可以在这句话里看出一些端倪:

$kernel->call( IKC => publish => $service_name, ["calc_sum"] );

函数call的第一个参数是session名称,所以Server就叫做IKC,简单得有点出乎意料,原本我以为为了保持唯一性可能会加上进程号之类的东西。在之后的结果里可以看到,客户端也是一个很简单的叫IKCLite的session名。

这句话其实就是IKC的功能所在,在涉及到IKC的程序中会大量地使用到这个结构的命令,可能是call也可能是post。call的命令会立即执行,而post的命令会被添加到事件队列的最后。这在我看来没有什么太大的差别,因为cpu已经够快了,而且大多数情况下事件的顺寻不存在逻辑关系。只是有一点会误导人的地方就是,例子的作者在涉及到远程调用时用到参数分隔符是“,”,而在本地调用中用到的是“=>”,但实际上“=>”和“,”在这句话里是没有差别的,我都换用过,结果没有任何影响。这么做可能为了在代码上更容易识别不同类型的调用。IKC这个session提供的publish,将其后的参数作为可别客户调用的命令发布出去,一旦有客户连接便可以得到对该命令使用的许可。既然说到了远程调用,那么还是举一个例子:

$_[KERNEL]->post('IKC','call', 'poe://AppServer/application/calc_sum', $num, 'poe:get_sum');

这是我自己写的客户端中一条用于验证对于rsvp结构猜测的指令,它将一串数字交给服务器端的calc_sum处理,并由本地的get_sum接收返回结果。正如前面讲到的,这里的分隔符变成了“,”,事实上毫无差别。不得不提的一点是其中的第三个参数,如果说这种形式的命令是IKC中的核心,那么第三个参数就是核心中的核心了,因为它说明了远程事件的确切地址。我们称它为rsvp。

rsvp

rsvp是Resource Reservation Protocol的简称,中文叫资源预留协议。如果你可以打开中文wiki的话,里面有很详细的解释,但这似乎很难。

还是回到上一节讲到的“poe://AppServer/application/calc_sum”。撇掉开始的“poe://”不说,这个地址可以分为三部分分别是kernel,session和state,在这了它们是Appserver,application和calc_sum。其中kernel是在初始化POE::Component::IKC::Server时作为参数被指定的,一般一个程序指定一个kernel。Application是业务session的名称,这在其触发_start事件时由alias_set来指定。最后的calc_sum是业务session中的一个事件,并被IKC的publish命令发布在核间。

再举一个例子。calc_sum的处理句柄将接受来自客户的rsvp,它实际上是和一连串数字结合在一起作为ARG0被传入的。可以看出来,这个ARG0内部包含了数组和哈希的引用,哈希引用就是rsvp。通过下面的命令可以大致揭示rsvp的内幕。

print $_, “ => ”, $rsvp->{$_}, “\n” foreach keys %$rsvp;

运行之后的结果如下:

kernel => Client904
session => IKCLite
state => response0

显然,这和我的猜测是相吻合的。好了,服务器端需要注意的差不多就是这些,下面来说说客户端。虽然相对来说客户端的程序简单了一些,但考虑到上面结果中state对应的内容是response0,于是难免让人不联想到客户端是不是还可以产生response1,2….

post_respond

客户端使用create_ikc_client命令来建立与服务器的连接,得到一个叫remote的POE::Component::IKC::ClientLite组建对象。这里要提一下的是这个组件可以用在不适合POE应用的场合,比如说mod_perl,来连接POE服务器。

之后,使用该对象的post_respond命令向服务器发送一串数组,表面上看的确如此。

my $return_value = $remote->post_respond( 'application/calc_sum', \@numbers );

但是,首先不同的一点是这里的所谓的“rsvp”是不完整的,它只由session和state构成,缺少了poe头和kernel;第二,它没有返回值处理函数。对于第一点,显然,post_respond为我们自动添加了缺失的部分;至于第二点,因为我们已经知道在服务器端将得到一个叫response0的state,那么这个response0便是post_respond自动创建的临时处理函数,它可能仅仅是这么一个结构:

s ub response0 { shift;  }

如果我们再增加另一组数字让服务器处理,那么post_respond产生的临时处理函数明会变成response1,以此类推。

#!/usr/bin/perl

use warnings;
use strict;

use POE qw(Session);
use POE::Component::IKC::Server;

POE::Component::IKC::Server->spawn(
    port => 31338,
    name => 'AppServer', # kernel name
);

POE::Session->create(
    inline_states => {
        _start => \&service_start,
        calc_sum => \&service_calc_sum,
        did_something => \&service_response,
    }
);

POE::Kernel->run();
exit 0;

sub service_start {
    my ( $kernel, $heap ) = @_[ KERNEL, HEAP ];
    
    my $service_name = "application";
    $kernel->alias_set($service_name);
    $kernel->call( IKC => publish => $service_name, ["calc_sum"] );
}

sub service_calc_sum {
    my ( $kernel, $heap, $request ) = @_[ KERNEL, HEAP, ARG0 ];
    my ( $data, $rsvp ) = @$request;
    
    #----------------
    print "@$request\n";
    print $_, " => ", $rsvp->{$_}, "\n" foreach keys %$rsvp;
    #----------------
    
    my $sum = 0;
    if ( ref($data) eq "ARRAY" ) {
        $sum += $_ foreach @$data;
    }
    
    $kernel->delay_set( did_something => 1, $rsvp, $sum );
}

sub service_response {
    my ( $kernel, $heap, $rsvp, $sum ) = @_[ KERNEL, HEAP, ARG0, ARG1 ];
    $kernel->call( IKC => post => $rsvp, $sum );
}

#!/usr/bin/perl

use warnings;
use strict;

use POE::Component::IKC::ClientLite;

my $name = "Client$$";
my $remote = create_ikc_client(
    port => 31338,
    name => $name,
    timeout => 10,
);
die $POE::Component::IKC::ClientLite::error unless $remote;

my @numbers = qw(8 5 6 2 3 9 0 1);
print "Summing : @numbers\n";

my $return_value = $remote->post_respond( 'application/calc_sum', \@numbers );
die $POE::Component::IKC::ClientLite::error unless defined $return_value;
print "The sum is : $return_value\n";

#----------------
@numbers = qw(8 8 3 0 4 1 6);
print "Summing : @numbers\n";
print "The sum is : ", $remote->post_respond( 'application/calc_sum', \@numbers ), "\n";
#----------------

exit 0;


posted on 2008-05-31 17:02 gyn_tadao 阅读(617) 评论(3)  编辑 收藏 引用 所属分类: perl

评论

# re: IKC初探 2008-06-03 17:54 35u54

<a title="婴儿游泳" href="http://www.njhanteng.com/">婴儿游泳</a>
<a title="网站推广" href="http://www.rudao.com/google.asp/">网站推广</a>
<a title="南京庆典" href="http://www.njyogapr.com/">南京庆典</a>
<a title="底盘装甲" href="http://www.liqui-moly.net.cn/">底盘装甲</a>
<a title="底盘装甲" href="http://www.liqui-moly.net.cn/product.asp">汽车添加剂</a>
<a title="南京水晶" href="http://www.audreyia.com/">南京水晶</a>
<a title="南京开业" href="http://www.njyogapr.cn/flash.html">南京开业</a>
<a title="南京活动" href="http://www.njyogapr.com/flash.htm">南京活动</a>
<a title="南京网络公司" href="http://www.rudao.com/about/index.asp">南京网络公司</a>
<a title="陶瓷金卤灯" href="http://www.jclight.cn/product1.asp">陶瓷金卤灯</a>
<a title="南京VI" href="http://www.longfine.net.cn/">南京VI</a>
<a title="婴儿游泳培训" href="www.njhanteng.com/peixun.asp" target="_blank">婴儿游泳培训</a>
<a title="伺服电机-伺服电机驱动器-伺服驱动器" href="http://www.zdrive.cn/aboutus.asp">伺服电机</a>">http://www.zdrive.cn/aboutus.asp">伺服电机</a>
<a title="伺服器-伺服电机-伺服电机驱动器" href="http://www.zdrive.cn/message.asp">伺服器</a>">http://www.zdrive.cn/message.asp">伺服器</a>
<a title="网站制作公司 扬州" href="http://www.rudao.net/">网站制作公司 扬州</a>
<a title="扬州分类信息" href="http://www.hi0514.com">扬州分类信息</a>
<a title="扬州旅游" href="http"//www.hi0514.com/tour/">扬州旅游</a>
<a title="扬州公交线路查询" href="http://www.hi0514.com/tour/Bus_BusSearch.asp">扬州公交线路查询</a>
<a title="扬州二手信息" href="http://www.hi0514.com/Info/Class_index.asp">扬州二手信息</a>
<a title="伺服电机-伺服电机驱动器-伺服驱动器" href="http://www.zdrive.cn/aboutus.asp">伺服电机</a>">http://www.zdrive.cn/aboutus.asp">伺服电机</a>
<a title="伺服器-伺服电机-伺服电机驱动器" href="http://www.zdrive.cn/message.asp">伺服器</a>">http://www.zdrive.cn/message.asp">伺服器</a>
<a title="转台" href="http://www.stroflight.com">转台</a>  回复  更多评论   

# re: IKC初探 2009-12-20 22:21 iakuf

研究得真深,有没有更多的poe的介绍啊  回复  更多评论   

只有注册用户登录后才能发表评论。
<2008年5月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

导航

统计

常用链接

留言簿(14)

随笔分类(126)

随笔档案(108)

相册

搜索

最新评论

阅读排行榜

评论排行榜