我注意到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层)已经将所有内容读取到内存中,数据仍处于挂起状态?
其他人也遇到过类似的问题吗?