LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1689|回复: 2

perl 双向管道 调用本地脚本问题

[复制链接]
发表于 2010-6-16 19:53:23 | 显示全部楼层 |阅读模式
程序目的是将一个输入导向一个本地的perl脚本, 再将这个脚本执行结果返回到当前的脚本, 使用open2双向管道操作, 但是总是不能成功, 请各位大大看看:

问题好像是本地脚本XXX.pl执行有问题, 因为是双向通信, 在IO上使用异步通信, select+sysread实现非阻塞的管道读取.


代码1, 主脚本代码:
  1. #!/usr/bin/perl -w
  2. use strict;
  3. BEGIN {
  4.         push(@INC, ".");
  5. }
  6. use FileHandle;
  7. use IPC::Open2;
  8. my %test_h = ();
  9. sub test {
  10.         my $in;
  11.         my $out;
  12.         #my $pid = open2($in, $out, "cat " );
  13.         my $pwd = `pwd`;
  14.         chomp($pwd);
  15.     my $pid = open2($test_h{"in"}, $test_h{"out"}, "./XXX1.pl" );
  16.         printf STDOUT ("%x %d    %x   %d\n", $test_h{"in"}, fileno($test_h{"in"}), $test_h{"out"}, fileno($test_h{"out"}));
  17.     while(1) {
  18.                 my $out = $test_h{"out"};
  19.                 printf $out ("%s", "stuff\n");                            #先向管道中输入一些字符串.
  20.                 printf $out ("stuff\n");
  21.                 my $in = $test_h{"in"};
  22.                 #my $got = <$in>;
  23.                 #my $got = <{$test_h{"in"}}>;
  24.                 #printf STDOUT ("WE GET: %s\n", $got);
  25.         my ($eof, @lines) = &nonblockGetLines($in);          #尝试从管道中进行读取,
  26.                 if($eof) { last; }
  27.                 foreach my $line (@lines) {
  28.                         printf STDOUT ("GOT: %s\n", $line);
  29.                 }
  30.         sleep(1);
  31.     }
  32. }
  33. # Returns:  ($eof,@lines)
  34. my %nonblockGetLines_last;
  35. sub nonblockGetLines {
  36.         my $fh = $_[0];
  37.         my $rfd = '';
  38.         $nonblockGetLines_last{$fh} = ''
  39.                 unless defined $nonblockGetLines_last{$fh};
  40.         #set file handle bit mask
  41.         vec($rfd, fileno($fh), 1) = 1;
  42.         #if something's coming
  43.         my $out_fd = 0;
  44.         if (not select($out_fd=$rfd, undef, undef, 0)>=0 )
  45.         {
  46.                 printf STDERR ("%x select not ready.\n", $fh);
  47.                 return (0);
  48.         }
  49.         printf STDERR ("OUT_FD:%x   IN_FD:%x  fileno: %d \n", ord($out_fd), ord($rfd), fileno($fh));
  50.    
  51.         ##        ##        ##        ##        ##        ##        ##        ##        ##
  52.         # 使用select+sysread进行nonblock的管道读取.
  53.         #   
  54.         #            这里$out_fd总是0, 即是说西面的XXX.pl没有print任何东西.
  55.         ##        ##        ##        ##        ##        ##        ##        ##        ##
  56.         if(not vec($out_fd, fileno($fh), 1)) {   
  57.                 printf STDERR ("%x not this one.\n", $fh);
  58.                 return (0);
  59.         }
  60.         my $buf = '';
  61.         my $n = sysread($fh, $buf, 1024*1024, 0);               
  62.         if ( ! defined $n ) {
  63.                 #on error, we just print an error message
  64.                 printf STDERR ("MAPPER: %x got a read error at input line.\n", $fh);
  65.         }elsif($n == 0) {
  66.                 # If we're done, make sure to send the last unfinished line
  67.                 return (1,$nonblockGetLines_last{$fh});
  68.         }
  69.         # Prepend the last unfinished line
  70.         $buf = $nonblockGetLines_last{$fh}.$buf;
  71.         # And save any newly unfinished lines
  72.         if(substr($buf,-1) !~ /[\r\n]/ && $buf =~ s/([^\r\n]*)$//) {
  73.                 $nonblockGetLines_last{$fh} = $1;
  74.         } else {
  75.                 $nonblockGetLines_last{$fh} = '';
  76.         }
  77.         return $buf ? (0,split(/\n/,$buf)) : (0);
  78. }
  79. &test();
复制代码

脚本2: 被调用的本地脚本XXX1.pl:
  1. #!/usr/bin/perl -w
  2. #
  3. while(<STDIN>) {    ###echo接收到的字符串
  4.         print "M2\t", $_;
  5. }
复制代码
 楼主| 发表于 2010-6-17 09:07:34 | 显示全部楼层
如果我将调用脚本的语句写成:

"cat"
那么程序是可以顺利打印出东西, 但是改成 "./XXX.pl" "perl ./XXX.pl" 都不行, 可以肯定的是XXX.pl是执行起来了的, 我在XXX.pl里面创建文件, 可以看到文件被创建了. 就是接收不到字符串.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-6-17 11:15:23 | 显示全部楼层
好像是buffer的问题, 不是不出东西, 我在XXX.pl里面设置
local $| = 1;
以后, 就可以得到输出了.

对管道通信还不熟, 有熟悉的大大可以讲讲为什么这里buffer不flush, 主脚本就一点数据都得不到吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表