perl中的套接字编程,perlio层有问题吗?

发布于 2024-09-05 03:09:04 字数 2475 浏览 3 评论 0原文

我注意到 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

薄凉少年不暖心 2024-09-12 03:09:04

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

从 perldoc -f select 中:

警告:不应尝试混合缓冲 I/O(例如
“read”或 ) 与“select”,除非 POSIX 允许,
即使这样也只能在 POSIX 系统上。你必须使用“sysread”
相反。

This is expected: if you're using select(), you need to use sysread() instead of read(), because of the buffering (as you've discovered :).

From perldoc -f select:

WARNING: One should not attempt to mix buffered I/O (like
"read" or ) with "select", except as permitted by POSIX,
and even then only on POSIX systems. You have to use "sysread"
instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文