coro::socket+coro::handle echo server(2)-sysread 的改造

前面的server是用getline实现的,想改用sysread实现

但是coro默认的sysread的行为是模拟系统的sysread,和我的需求不太一样

我希望是指定读取nbyte的字符,如果不满nbyte,就全部返回,为空就等待

而sysread会等待达到指定长度直到超时

需要对sysread对应的READ方法作如下修改

 

sub READ {
   my $len = $_[2];
   my $ofs = $_[3];  #偏移量,默认为0
   my $res;

   # first deplete the read buffer
   if (length $_[0][3]) {
      my $l = length $_[0][3];
      if ($l <= $len) { #收到数据不足指定长度,buf为数据,,返回值为长度
         substr ($_[1], $ofs) = $_[0][3]; $_[0][3] = "";
         $len -= $l;
         $ofs += $l;
         $res += $l;
        # return $res unless $len; #原来只有读够才返回
        return $res if $l;
      } else { #超过指定长度,返回部分.返回值为长度,数据在buf
         substr ($_[1], $ofs) = substr ($_[0][3], 0, $len);
         substr ($_[0][3], 0, $len) = "";
         return $len;
      }
   }

   while() {
      my $r = sysread $_[0][0], $_[1], $len, $ofs;
      
      if (defined $r) {
         $len -= $r;
         $ofs += $r;
         $res += $r;
         ######################增加eof的处理
         if($r ==0 ){
          # EOF
            return 0 unless length $_[0][3];
         }   
         ######################
         #last unless $len && $r;  #原来只有读够或者没读到,才返回,
         last if $r; #改为if $r,只要有返回就last
      } elsif ($! != EAGAIN && $! != EINTR && $! != WSAEWOULDBLOCK) {
         last;
      }
      last if $_[0][8] || !&readable;
   }

   $res
}


 

 

为了不改动原有的sysread功能,我参照readline实现了一个新的READSTR方法,就通过原来的read接口(反正原来read和sysread是一样的)

感觉这样更好一些

#目标:实现一个类似getline的方法,读到指定长度或者buf为空就返回,不判断超时
sub READSTR {
   my $len = $_[2];
   my $ofs = $_[3];
   my $res;
   while () {
   	 my $len = sysread $_[0][0],$_[0][3], $len, $ofs;
   	 unless ($len) {
         if (defined $len) {
            # EOF
            return undef unless length $_[0][3];



            return delete $_[0][3];
         } elsif (($! != EAGAIN && $! != EINTR && $! != WSAEWOULDBLOCK) || !&readable) {
            return length $_[0][3] ? delete $_[0][3] : undef;
         }
      }
      if (length $_[0][3]) {
        my $l = length $_[0][3];
        if ($l <= $len) { #不足指定长度,全部返回
        	return delete $_[0][3];
        }	
        else{#超过指定长度,返回部分
        	 $res = substr ($_[0][3], 0, $len);
        	 #清空部分buf
           substr ($_[0][3], 0, $len) = "";
           return  $res;
        }
      }
  }	

}


使用该方法改造的coro echo server

#!/bin/env perl
#sever coro::socket+coro::handle来实现
#不使用getline,改为sysread(不完美)
use strict;
use Coro;
use AnyEvent;
#这个是ae的perl实现,要比EV慢一点点
use AnyEvent::Impl::Perl;
use Coro::Socket;
use Coro::Handle; 


my $port   = 11212;


#1.创建监听端口
$|++;  # 因为print到终端,所以这里要打开autoflush
my $s = Coro::Socket->new(LocalAddr => 'localhost',  # 创建一个侦听socket
                              LocalPort =>  $port,
                              Listen    => 5,
                              Proto     => 'tcp')
        or die $@;
        
        
#2.处理handle
my @coro;
while(1){
	 my ($fh, $peername)  = $s->accept;
	 next unless  $peername;
	 print "accepet new sock at" . $fh->fileno . "\n";
	 
	 &doit($fh);
	 
}   
	 

sub doit($){
	my ($fh)=@_;
	
	push @coro, async {
	 	$fh->autoflush(1);
   
    my $line="";
	 	#while(my $line=$fh->readline()){
	 	#while(my $ret=$fh->sysread($line,64)){
	 	#while($fh->readable){
	 	while(my $line=$fh->read($buf,32)){	
       #my $line=$fh->readline(); 
       #my $ret=$fh->recv($line,32);       
       #my $ret=$fh->sysread($line,32); 
        print $fh->fileno, " ", $line, " ";
        $fh->print($line);          
        
      }   
            print "no more data, close socket " . $fh->fileno . "\n";
            $fh->close;
            #关闭协程
            return;        
	 }	
	 
}

  


说明,在这个地方卡了很久.

对coro的readble,sysread这些方法理解不透.(不明白从原来的阻塞方式改为现在的非阻塞方式究竟有哪些变化)

作者只是一句Work like their function equivalents轻轻带过(囧阿,similar...)

后来还是参照源码,添加打印信息,一点点摸索.

目前还是对readable的实现不理解,感觉不像作者说的

Wait until the filehandle is readable or writable (and return true) or
until an error condition happens (and return false).
而是始终为true.

否则用readable配合recv等直读方法也是可以的

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值