perl coro socket编程(1)

coro提供了perl的非阻塞io.但是作者提供的文档太简略了,例子也没有.

自己尝试写了几个例子.

分别实现CU上仙子提供的例子以及AE自带的echo server例子

相关的模块有

coro:;socket,coro::handle

ae::socket,ae::handle

 

先看看传统的socket编程(CU上仙子提供的例子)

客户端使用多进程并发

use strict;
use IO::Socket;

my @childs;
   
for (1..3) {  # fork 3个子进程,同时发送数据

   my $child = fork;
   if ($child) {
      push(@childs, $child);

   } else {
     # 创建到server的连接socket
      my $sock=IO::Socket::INET->new(PeerAddr => 'localhost',
                               PeerPort => 1234,
                               Proto    => 'tcp') or die $@;

      for (1..10) {  # 每个子进程里,发送10次数据
          print $sock  random() . "\n";
          select(undef, undef, undef, 0.25);  # 每发送一次,就休眠0.25秒
      }

      $sock->close or die $!;  # 发送完后关闭socket,并退出子进程
      exit 0;
   }
}

for (@childs) {  # 回收子进程
    my $tmp = waitpid($_, 0);
    print "done with pid $tmp\n";
}   

sub random {  # 该函数产生随机字串
    my @x=(0..9,'a'..'z','A'..'Z');
    join '',map {$x[int rand @x]} 1..49;  # 返回49字节长度的串
}


服务器端使用select复用模式

use strict;
use IO::Socket;
use IO::Select;

$|++;  # 因为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的检查队列

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);

     # 使用sysread读取数据,每次读取32字节,并且只处理这32字节
     # 如果客户端发送多于32字节的数据包,会分几次处理,如果几个客户端同时发送,处理过程是无序的
     # 避免使用<>方式读取socket,因为<>面向行读取,perlio对它做了缓冲,IO::Select看不到这个缓冲
     }else {
        my $buf = undef;
        if (sysread($rh,$buf,32)) {
            print $rh->fileno, " ", $buf, " ";

        # sysread的返回是读取的字节数量,如果返回0,则说明抵达文件末尾(EOF)
        # 如果sysread返回0,那么说明客户端关闭socket,我们从检查队列里删除该句柄,同时关闭socket句柄
        } else {
            print "no more data, close socket " . $rh->fileno . "\n";
            $read_set->remove($rh);
            $rh->close;
        }
     }
  }
}


下面使用coro来进行改造

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值