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

这个其实只有理论上的意义,方便了解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到终端,所以这里要打开autoflush
my $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;
      }
    }
	 }     
}
	


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值