代码之家  ›  专栏  ›  技术社区  ›  dlamotte

Perl中的socket编程,Perlio层有问题吗?

  •  1
  • dlamotte  · 技术社区  · 14 年前

    我注意到Perl中Perlio层存在一些问题。我花了一天时间才找到它,希望其他人知道一些关于它的事情?最可怕的是,由于它是如此低级,我担心它会降低代码的可移植性。

    服务器代码:

    use strict;
    use Socket;
    
    socket(my $sock, AF_INET, SOCK_STREAM, getprotobyname('tcp')) or die();
    setsockopt($sock, SOL_SOCKET, SO_REUSEADDR, 1) or die();
    bind($sock, pack_sockaddr_in(23457, inet_aton('0.0.0.0'))) or die();
    listen($sock, 10) or die();
    
    my $paddr = accept(my $csock, $sock);
    if (not $paddr) { 
        die();
    }
    my ($port, $iaddr) = unpack_sockaddr_in($paddr);
    printf "accepted %s:%s\n", inet_ntoa($iaddr), $port;
    send($csock, "1234567890", 0);
    recv($csock, my $tmp, 8192, 0);
    close($csock);
    close($sock);
    

    客户机代码(我会稍微更改以进行测试):

    use strict;
    use Socket;
    use PerlIO;
    
    socket(my $sock, AF_INET, SOCK_STREAM, getprotobyname('tcp')) or die();
    connect($sock, pack_sockaddr_in(23457, inet_aton('localhost'))) or die();
    print "layers before = ".join(', ', PerlIO::get_layers($sock))."\n";
    #binmode($sock, ':pop');  # uncomment this line to watch the code work...
    print "layers after  = ".join(', ', PerlIO::get_layers($sock))."\n";
    
    my $tmp;
    print "1ret    = ".read($sock, $tmp, 1)."\n"; print "tmp $tmp\n"; stillpending($sock);
    print "1ret    = ".read($sock, $tmp, 1)."\n"; print "tmp $tmp\n"; stillpending($sock);
    print "1ret    = ".read($sock, $tmp, 1)."\n"; print "tmp $tmp\n"; stillpending($sock);
    print "1ret    = ".read($sock, $tmp, 1)."\n"; print "tmp $tmp\n"; stillpending($sock);
    print "8192ret = ".read($sock, $tmp, 8192)."\n"; print "tmp $tmp\n"; stillpending($sock);
    send($sock, 'blah', 0);
    
    close($sock);
    

    服务器输出:

    accepted 127.0.0.1:39944
    

    带binmode注释的客户端输出(使用Perlio层):

    layers before = unix, perlio
    layers after  = unix, perlio
    1ret    = 1
    tmp 1
    no more
    1ret    = 1
    tmp 2
    no more
    1ret    = 1
    tmp 3
    no more
    1ret    = 1
    tmp 4
    no more
    

    永远在街区之上。

    未注释binmode的客户端输出(没有使用Perlio层):

    layers before = unix, perlio
    layers after  = unix
    1ret    = 1
    tmp 1
    still more
    1ret    = 1
    tmp 2
    still more
    1ret    = 1
    tmp 3
    still more
    1ret    = 1
    tmp 4
    still more
    8192ret = 6
    tmp 567890
    no more
    

    我的问题是 select() 当第一个read()调用显然(通过strace)消耗了服务器发送的整个输出(我想象的是,在某个内部缓冲区中)时,停止返回挂起的数据。最后一个 read(..., 8192) 当没有perlio层时也会阻塞,它不会阻塞。

    我想我已经解决了我的问题(打开Perlio层),但是我很好奇其他人的想法是什么?是不是一个虫子 选择() 报告 no more 即使第一个Perl读取(带有Perlio层)已经将所有内容读取到内存中,数据仍处于挂起状态?

    其他人也遇到过类似的问题吗?

    1 回复  |  直到 14 年前
        1
  •  8
  •   psmears Touffy    14 年前

    这是预期的:如果你正在使用 select() ,您需要使用 sysread() 而不是 read() ,因为缓冲(正如您发现的那样:)。

    perldoc -f select :

    警告:不应尝试混合缓冲I/O(如 “读取”或)带“选择”,除非POSIX允许, 甚至只有在POSIX系统上。您必须使用“SysRead” 相反。