perl中的套接字编程,perlio层有问题吗?
我注意到 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
我的问题是,当显然(通过 strace)第一个 read() 调用消耗了整个输出时,select()
停止返回待处理的数据由服务器发送(我想象到一些内部缓冲区)。当没有 perlio 层时,最后一个 read(..., 8192) 也会阻塞,它不会阻塞。
我想我已经解决了我的问题(弹出 perlio 层),但我很好奇其他人的想法是什么?即使第一个 Perl 读取(使用 Perlio 层)已将所有内容读入内存,select()
报告没有更多
数据挂起,这是否是一个错误?
还有其他人遇到过类似的问题吗?
I'm noticing some problems with the perlio layer in perl. Took me a good day to track it down and was hoping some other people knew something about this? The scariest thing about this is that since its so low-level, I'm worried it'll reduce the code's portability.
Server code:
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);
Client code (that I change slightly to test):
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);
Server output:
accepted 127.0.0.1:39944
Client output with binmode commented (perlio layer in use):
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
Above blocks forever.
Client output with binmode uncommented (no perlio layer in use):
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
My problem is that select()
stop returning that data is pending when obviously (via strace) the first read() call has consumed the entire output sent by the server (into some internal buffer I imagine). Upon which the last read(..., 8192)
will also block when without the perlio layer, it does not block.
I guess I have the solution to my problem (pop the perlio layer), but I'm curious what other peoples thoughts are? Is it a bug that select()
reports no more
data pending even though the first perl read (with perlio layer) has read everything into memory?
Has anyone else run into similar issues?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是预期的:如果您使用
select()
,则需要使用sysread()
而不是read()
,因为缓冲(正如您所发现的:)。从 perldoc -f select 中:
This is expected: if you're using
select()
, you need to usesysread()
instead ofread()
, because of the buffering (as you've discovered :).From
perldoc -f select
: