转载本站文章请注明,转载自:扶凯[http://www.php-oa.com]
本文链接: http://www.php-oa.com/2009/09/09/perl-poe-1.html
Kernel
|
Session
| _______________________________ |
| | |
Driver->Filter->Wheel->Components Kernel:
POE管理会话的内核Kernel,它是POE核心,内部实现了IO读写信号回调等处理,简单应用程序与Kernel交互并不多。 Session: 会话抽象,会话中需要创建高层协议抽象,Session是一个处理线程,比如一个服务器程序每一个客户端连接就应该对应于一个Session,同理 Spider程序中对于每一个web服务器的连接也应该对应于一个Session,一个应用程序可以有很多Session。
Driver: 底层文件操作的抽象,在编程时不会直接用到,Wheel、Filter、Driver是对底层IO的封装。
Filter: 底层、中层协议操作的抽象,通常不会直接用到
Wheel: 高层协议操作的抽象,经常要用到
Components:POE提供的一些拿来就能用的组件
my ($kernel, $session, $heap) = @_[ KERNEL, SESSION, HEAP ]; my ($currentItem,$count) = @_[ ARG0..$#_ ];
如上,这是事件调用后,比较建议给通用的信息放到第一行.第二行是其它参数接收方法,这个中 @_[ ARG0..$#_ ],很象普通的子函数调用@_一样.
my ($kernel, $session, $heap) = @_[ KERNEL, SESSION, HEAP ]; my ($currentItem,$count) = @_[ ARG0..$#_ ];
现在我们来拿Flw大大的程序来分析POE的工作原理. 注意,在这个程序基本上可以分为三部分
1) POE::Session->create,创建一个Session。
2) POE::Kernel->run, 启动框架消息分发。
3) sub start … 定义各种状态的回调函数。
use POE; create POE::Session( inline_states => { _start => \&session_start, _stop => \&session_stop, count => \&session_count, } ); print "启动 POE 内核...\n"; POE::Kernel->run(); print "POE 内核运行结束。\n"; exit; sub session_start { print "Session 启动。Session ID = ", $_[SESSION]->ID, "\n"; $_[HEAP]->{count} = 0; $_[KERNEL]->yield("count"); } sub session_stop { print "Session 停止。Session ID = ", $_[SESSION]->ID, ".\n"; } sub session_count { my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; my $session_id = $_[SESSION]->ID; $heap->{count}++; printf "计数器 = %s\n", $heap->{count}; if ( $heap->{count} < 5 ) { $kernel->yield("count"); } }
use POE; #加载了一些诸如POE::Kernel和POE:Sesson的模块并相应地做了一些初始化,并由POE::Session会根据不同的事件输出默认常 量给事件句柄的某些参数,如:KERNEL,HEAP,ARG0等等。
1.建立session 接着建立至少一个session。程序最少要有事情可以做.不然POE::Kernel会在最后一个session停止以后终止运行。
create POE::Session( inline_states => { _start => \&session_start, _stop => \&session_stop, count => \&session_count, } );
其中的inline_states(HASHREF)表示将事件名映射到处理该事件的代码引用。还有一个 object_states(LISTREF)将事件名映射到处理它们的对象方法,值是对象引用和对象方法引用组成的列表的引用。 两个事件(最上面提到的事件句柄)是由POE::Kernel自身所提供的。它们分别表示该session的启动(_start)和销毁(_stop)。 最后一个事件(count)是用户自定义事件,它被用于程序的逻辑之中。下面我们会来亲自写这几个函数.
2.启动POE::Kernel 由此便建立了一个用来探测并分派事件的主循环。我们使用print来打印POE::Kernel运行的开始处和结束点。
print "启动 POE 内核...\n"; POE::Kernel->run(); print "POE 内核运行结束。\n"; exit;
Kernel的run方法只有在所有session返回之后才会停止循环。
3.由上面定义的3个事件句柄:
_start句柄 在上面建立session的时候.首先从_start开始。_start的句柄将在sesson初始化完成之后开始运行,session在其自身的上下文 中使用它来实现输入引导。比如初始化heap中的值,或者分配一些必要的资源等等。 在该句柄中我们建立了一个累加器,并且发出了“count”事件以触发相应的事件句柄。
sub session_start { print "Session 启动。Session ID = ", $_[SESSION]->ID, "\n"; $_[HEAP]->{count} = 0; $_[KERNEL]->yield("count"); }
在这,我们使用yield方法,将一个事件放入fifo分派队列的末尾处,当队列中在其之前的事件被处理完毕之后,该事件将被触发以运行相应的事件 句柄。
_stop句柄。 POE::Kernel将在所有session再无事件可触发之后,并且是在自身被销毁之前调用它。
sub session_stop { print "Session 停止。Session ID = ", $_[SESSION]->ID, ".\n"; }
count事件句柄。 该函数用来增加heap中的累加器计数,并打印累加结果。为了加深对yield的印象,我们现在使用yield方法来调用新的事件,这样也能够加深对 POE事件处理原理的理解。
sub session_count { my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; my $session_id = $_[SESSION]->ID; $heap->{count}++; printf "计数器 = %s\n", $heap->{count}; if ( $heap->{count} < 5 ) { $kernel->yield("count"); } }
POE输出:只要累加器计数未超过10,session将再yield一个count事件。因为不断地触发了 session_count句柄,使得当前session可以继续得以生存而不会被POE::Kernel清理。 当计数器到10时,便不再调用yield命令,session也将停止。一旦POE::Kernel检测到该session再没有事件句柄可被激发,便在 调用_stop事件句柄之后将其清理销毁。 以下是运行的结果:
Session 启动。Session ID = 2 启动 POE 内核... 计数器 = 1 计数器 = 2 计数器 = 3 计数器 = 4 计数器 = 5 Session 停止。Session ID = 2. POE 内核运行结束。
有没有注意到,第一个count时本来是要打印0的,但是直接打印1.为什么,主要是因为下面,yield是需要事件完后才调用.
session->get_heap() 通过 session 来得到 heap.
POE::API::Peek 这是一个可以查看 POE 核心事件的接口
POE::Wheel::Run 制造轮子,常用来做并发的事件
POE::Filter::Line 行过滤器
POE::Wheel::SocketFactory 非阻塞套接字创建
POE::Component::Server::TCP 一个简单的TCP服务器
POE::Wheel::ListenAccept