Я заметил некоторые проблемы со слоем perlio в perl. У меня был хороший день, чтобы отследить это и надеяться, что другие люди что-то знали об этом? Самое страшное в этом то, что, поскольку он настолько низкоуровневый, я боюсь, что это снизит переносимость кода.
Код сервера:
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 layer):
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
Над блоками навсегда.
Вывод клиента без комментария в бинмоде (без использования 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()
перестает возвращать эти данные в ожидании, когда очевидно (через strace) первый вызов read () израсходовал весь вывод, отправленный сервером (во некоторый внутренний буфер, который я представляю). После чего последний read(..., 8192)
также будет блокироваться, если без слоя perlio он не блокируется.
Полагаю, у меня есть решение моей проблемы (добавьте слой perlio), но мне интересно, что думают другие люди? Является ли ошибкой то, что select()
сообщает no more
данные, ожидающие обработки, даже при первом чтении perl (со слоем perlio) прочитало все в память?
Кто-нибудь еще сталкивался с подобными проблемами?