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

来源:互联网 发布:淘宝图片上传软件 编辑:程序博客网 时间:2024/06/01 12:32

前面的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到终端,所以这里要打开autoflushmy $s = Coro::Socket->new(LocalAddr => 'localhost',  # 创建一个侦听socket                              LocalPort =>  $port,                              Listen    => 5,                              Proto     => 'tcp')        or die $@;                #2.处理handlemy @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等直读方法也是可以的

 

原创粉丝点击