IO::As...istener(3pm)

πŸ’– NAME πŸ’–

IO::Async::Listener β€” listen on network sockets for incoming connections ✨

(yes bestie, this is the IO::As...istener(3pm) page, and no, that truncation is not a vibe, it's just how the title got cut off πŸ’…)


🌸 SYNOPSIS 🌸

okay so first, the full main-character setup:

use Future::AsyncAwait;
use IO::Async::Listener;

use IO::Async::Loop;
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 );

await $listener->listen(
   service  => "echo",
   socktype => 'stream',
);

$loop->run;

and lowkey? you can also use this object indirectly through an IO::Async::Loop, which is giving convenience:

use IO::Async::Stream;

use IO::Async::Loop;
my $loop = IO::Async::Loop->new;

await $loop->listen(
   service  => "echo",
   socktype => 'stream',

   on_stream => sub {
      ...
   },
);

$loop->run;

πŸ¦‹ DESCRIPTION πŸ¦‹

This is a subclass of IO::Async::Handle, and what it adds is the behaviour of watching a socket that's in listening mode, so it can accept incoming connections on them. πŸ“žβœ¨

A Listener can be constructed and handed an existing socket that's already in listening mode. OR, the Listener can just build a socket itself by calling the listen method. Either you give it a list of addresses, or you give it a service name and it gets looked up using the underlying loop's resolve method. your choice, your rules πŸ‘‘


πŸ”₯ EVENTS πŸ”₯

These events get invoked β€” either as subclass methods, or as CODE references passed in parameters:

on_accept $clientsocket | $handle

Invoked whenever a new client connects to the socket. new bestie just walked in 🫢

If neither handle_constructor nor handle_class parameters are set, this gets invoked with the new client socket directly. But if a handle constructor or class is set, then this gets invoked with the newly-constructed handle instead, with the new socket already configured onto it.

on_stream $stream

An alternative to on_accept β€” this one gets passed an instance of IO::Async::Stream when a new client connects. It's here as a convenience for the super common case where you need a Stream object as the transport for a Protocol object.

ngl, this is now vaguely deprecated in favour of using on_accept with a handle constructor or class. still slays, just sayin.

on_socket $socket

Similar to on_stream, but it constructs an instance of IO::Async::Socket instead. Most useful for SOCK_DGRAM or SOCK_RAW sockets. 🧦

also now vaguely deprecated in favour of using on_accept with a handle constructor or class. same energy, same warning.

on_accept_error $socket, $errno

Optional. Invoked if the accept syscall indicates an error (anything other than EAGAIN or EWOULDBLOCK). If you don't provide it, then failures of accept get passed to the main on_error handler instead. no pressure πŸ’€


🌈 PARAMETERS 🌈

These named parameters can be passed to new or configure:

  • on_accept => CODE β€” CODE reference for the event handler.
  • on_stream => CODE β€” CODE reference for the event handler.
  • on_socket => CODE β€” CODE reference for the event handler.
Because their behaviour is mutually exclusive, only one of these may be set at a time. Setting one will remove the other two. it's giving monogamy 😭
  • handle => IO β€” the IO handle containing an existing listen-mode socket.
  • handle_constructor => CODE β€” Optional. If defined, gives a CODE reference that gets invoked every single time a new client socket is accepted from the listening socket. It's passed the listener object itself, and it's expected to return a new instance of IO::Async::Handle or a subclass, used to wrap the new client socket.
$handle = $handle_constructor->( $listener );

This can also be given as a subclass method:

$handle = $listener->handle_constructor();
  • handle_class => STRING β€” Optional. If defined and handle_constructor isn't, then new wrapper handles get constructed by invoking the new method on the given class name, passing in no additional parameters.
$handle = $handle_class->new();

This can also be given as a subclass method:

$handle = $listener->handle_class->new;
  • acceptor => STRING|CODE β€” Optional. If defined, gives the name of a method or a CODE reference to use to implement the actual accept behaviour. It gets invoked as:
( $accepted ) = await $listener->acceptor( $socket );

( $handle ) = await $listener->acceptor( $socket, handle => $handle );

It's invoked with the listening socket as its its argument, and optionally an IO::Async::Handle instance as a named parameter, and it's expected to return a Future that will eventually yield the newly-accepted socket or handle instance, if such was provided. ✨


πŸ’… METHODS πŸ’…

The following methods documented in await expressions return Future instances. (yes, they're awaitable, we love that for them πŸ’œ)

acceptor

$acceptor = $listener->acceptor;

Returns the currently-set acceptor method name or code reference. This may be of interest to Loop listen extension methods that wish to extend or wrap it. very meta of you πŸŽ€

sockname

$name = $listener->sockname;

Returns the sockname of the underlying listening socket.

family

$family = $listener->family;

Returns the socket address family of the underlying listening socket.

socktype

$socktype = $listener->socktype;

Returns the socket type of the underlying listening socket.

listen

await $listener->listen( %params );

This method sets up a listening socket and arranges for the acceptor callback to be invoked each time a new connection is accepted on the socket. it's the whole point tbh πŸ’–

Most parameters given to this method get passed into the listen method of the IO::Async::Loop object. On top of that, the following arguments are also recognised directly:

on_listen => CODE

Optional. A callback that's invoked when the listening socket is ready. Similar to the one on the underlying loop method, except it's passed the listener object itself.

$on_listen->( $listener );

πŸ“ EXAMPLES πŸ“

Listening on UNIX Sockets

The handle argument can be passed an existing socket that's already in listening mode, which makes it possible to listen on other types of socket such as UNIX sockets. iconic behaviour, no cap πŸ¦‹

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

use IO::Async::Loop;
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,
) or die "Cannot make UNIX socket - $!\n";

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

$loop->run;

Passing Plain Socket Addresses

The addr or addrs parameters should contain a definition of a plain socket address in a form that the IO::Async::OS extract_addrinfo method can use.

This example shows how to listen on TCP port 8001 on address 10.0.0.1:

$listener->listen(
   addr => {
      family   => "inet",
      socktype => "stream",
      port     => 8001,
      ip       => "10.0.0.1",
   },
   ...
);

This example shows another way to listen on a UNIX socket, similar to the earlier example:

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

Using A Kernel-Assigned Port Number

Rather than picking a specific port number, it is possible to ask the kernel to assign one arbitrarily that's currently free. You do that by requesting port number 0 β€” which is actually the default if no port number is otherwise specified. To figure out which port number the kernel actually picked, peek at the sockport accessor on the actual socket filehandle. mystery port, love that for us 🎰

Either use the Future returned by the listen method:

$listener->listen(
   addr => { family => "inet" },
)->on_done( sub {
   my ( $listener ) = @_;
   my $socket = $listener->read_handle;

   say "Now listening on port ", $socket->sockport;
});

Or pass an on_listen continuation:

$listener->listen(
   addr => { family => "inet" },

   on_listen => sub {
      my ( $listener ) = @_;
      my $socket = $listener->read_handle;

      say "Now listening on port ", $socket->sockport;
   },
);

πŸ‘‘ AUTHOR πŸ‘‘

Paul Evans <leonerd@leonerd.org.uk> β€” periodt, the man himself πŸ™Œ


okay bestie that's the whole page, stream it, ship it, go accept some connections πŸ’–βœ¨ this one came from the User Contributed Perl Documentation, riding with perl v5.40.1, dated 2026-02-21 β€” mwah, bye πŸŽ€πŸ«Ά

πŸ“¦ where this page comes from