coro+io::select实现无阻塞server (测试server)

来源:互联网 发布:淘宝店铺怎么改发货地 编辑:程序博客网 时间:2024/05/16 19:39

这个其实只有理论上的意义,方便了解coro的原理

实际上既然用了select ,再用coro反而显得很笨拙.

#!/bin/env perl#select sever coro版(ok)#换一种写法,每个连接起一个协程#因为select直接可以得到有数据的socket#所以可以用cede_to,直接唤醒对应的协程#主要演示一下cede_to和schedule的用法(类似lua和python)#没有用到coro的自动调度use strict;use IO::Socket;use IO::Select;use Coro;#1.创建监听端口$|++;  # 因为print到终端,所以这里要打开autoflushmy $s = IO::Socket::INET->new(LocalAddr => 'localhost',  # 创建一个侦听socket                              LocalPort => 1234,                              Listen    => 5,                              Proto     => 'tcp')        or die $@;my $read_set = new IO::Select();   # 创建一个IO::Select目标$read_set->add($s);   # 把上述侦听socket加入IO::Select的检查队列my @coro;my %table;my $conum=0;while (1) {   # 一个死循环   # IO::Select有一个静态select方法,第一个参数如果设置,表示检查可读的socket   # 该方法一直block,直到有可用的句柄返回   # 返回一个三参数列表,第一个参数表示可读的socket句柄集合(一个数组引用)  my ($rh_set) = IO::Select->select($read_set, undef, undef, undef);         foreach my $rh (@$rh_set) {  # 遍历可读的socket     # 如果当前可读的socket等于侦听socket,那么说明有新请求进来,应该及时accept     # accept后,把已建立连接的socket句柄加入检查队列     if ($rh == $s) {        my $ns = $rh->accept();        $read_set->add($ns);        print "accepet new sock at" . $ns->fileno . "\n";         #为每个连接创建单独的协程                &doit($ns);             }       #如果是已有的socket,那么切换到协程(不需要指定具体协程,由coro调度实现)     else{     #print "receive data on existing sock.\n";                  my $coi= $table{$rh->fileno}-1;       $coro[$coi]->resume;       $coro[$coi]->cede_to;     }     #协程调度     #cede;   }}  #协程的处理sub doit($){ my ($rh)=@_; my $fno=$rh->fileno; #print "receive data on existing sock " . $rh->fileno . "\n";#if($table{$fno} > 0){#return; #} print "new coro $fno.\n"; $conum++; $table{$fno} =$conum; push @coro, async {  # 使用sysread读取数据,每次读取32字节,并且只处理这32字节     # 如果客户端发送多于32字节的数据包,会分几次处理,如果几个客户端同时发送,处理过程是无序的     # 避免使用<>方式读取socket,因为<>面向行读取,perlio对它做了缓冲,IO::Select看不到这个缓冲   my $buf = undef;   while(1){      if (sysread($rh,$buf,32)) {            print $rh->fileno, " ", $buf, " ";            #每处理32byte切换            #cede;            schedule;      }         else{        # sysread的返回是读取的字节数量,如果返回0,则说明抵达文件末尾(EOF)        # 如果sysread返回0,那么说明客户端关闭socket,我们从检查队列里删除该句柄,同时关闭socket句柄            print "no more data, close socket " . $rh->fileno . "\n";            $read_set->remove($rh);            $rh->close;                       #关闭协程            return;      }    } }     }


 

原创粉丝点击