Как удалить объект IO::Async::Listener (или его уведомителя) из события IO::Async::Loop в perl

У меня есть кусок кода, который создает сокет домена UNIX с помощью IO::Socket::UNIX и передает его экземпляру IO::Async::Listener для обработки прослушивания сокета и уведомления о получении данных. Затем IO::Async::Listener добавляется к экземпляру цикла событий IO::Async::Loop. Разумеется, сокеты создаются динамически в управляемом менеджере.

При определенных условиях я хотел бы удалить сокет из цикла событий (полностью удалить его или временно отключить его при других условиях, если это возможно), но я не знаю как.

IO::Async::Loop предлагает удалить объекты IO::Async::Notifier из цикла событий с помощью $loop->remove( $notifier), но создание уведомителя было обработано внутри IO::Async::Listener (через IO:: Async:: Stream, я полагаю?). Даже на Ctrl-C моего скрипта файл сокета не удаляется, мне просто нужно вручную close $socket and unlink( $path ) файла сокета?

Вот абстрактный код желаемого поведения:

#!/usr/bin/perl

use IO::Async::Loop;
use IO::Async::Listener;
use IO::Socket::UNIX;

my $loop = IO::Async::Loop->new;
my $listener = IO::Async::Listener->new(
                    on_stream => sub {
                            my ( undef, $stream ) = @_;

                            $stream->configure(
                                    on_read => sub {
                                            my ( $self, $buffref, $eof ) = @_;
                                            $self->write( $buffref );
                                            $buffref = "";
                                            return 0;
                                    },
                            );

                            $loop->add( $stream );
                    },
            );
$loop->add( $listener );

my $socket = IO::Socket::UNIX->new(
            Local => "echo.sock",
            Listen => 1,
            ) || die "Cannot make UNIX socket - $!\n";

$listener->listen(
            handle => $socket,
            );

my $condition = true;

while($condition) {
            // this is probably wrong
            $loop->remove( $listener );
            $condition = false;
}

1 ответ

Решение

Кажется, у вас есть два связанных вопроса.

Вы можете удалить объект слушателя из цикла, используя цикл remove метод:

$loop->remove( $listener )

Однако удаление слушателя из цикла не приведет к отсоединению узла сокета от файловой системы. Для этого вам понадобится unlink код, который вы предложили.

Лично в таком коде, который создает подобные сокеты, я использую END блок:

my $path = "echo.sock";
my $socket = IO::Socket::UNIX->new(
            Local => $path,
            Listen => 1,
            ) || die "Cannot make UNIX socket - $!\n";
END { $socket and unlink $path }
$SIG{INT} = $SIG{TERM} = sub { exit 1 };

$SIG линия требуется, чтобы убедиться, что SIGINT а также SIGTERM еще запустить END блокировать, а не просто вызывая perl Процесс немедленно прекратить.

Наконец, вы должны отметить, что вы можете использовать более аккуратную форму listen метод, а не явно создавая UNIX гнездо в вашем случае можно просто

my $listener = ...
$loop->add( $listener );

$listener->listen(
  addr => {
    family   => "unix",
    socktype => "stream",
    path     => "echo.sock",
  },
);

Хотя опять же в этом случае вам все равно понадобится END блок.

Другие вопросы по тегам