NAME
Linux::Event::IO::Sock::Listener - Accept asynchronous stream connections
SYNOPSIS
use v5.36;
use Linux::Event::Loop;
use Linux::Event::IO::Sock::Listener;
my $loop = Linux::Event::Loop->new;
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
host => '127.0.0.1',
port => 9999,
stream => {
on_data => sub ($self, $bytes) {
$self->write($bytes);
},
},
);
say "Listening on port " . $listener->port;
$loop->run;
DESCRIPTION
Linux::Event::IO::Sock::Listener represents a listening stream socket.
It accepts incoming connections and creates a Linux::Event::IO::Sock::Stream object for each one.
A Listener can listen on:
TCP over IPv4
TCP over IPv6
Unix-domain stream sockets
an already-created listening socket supplied by the application
The most important Listener option is stream.
The stream hash describes what kind of Stream should be created for each accepted connection and how that Stream should behave.
For example, this creates a simple echo server:
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
host => '0.0.0.0',
port => 9000,
stream => {
on_data => sub ($self, $bytes) {
$self->write($bytes);
},
},
);
Every new client gets its own Stream object, and that Stream uses the supplied on_data callback.
CREATING A TCP LISTENER
A normal TCP server looks like this:
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
host => '0.0.0.0',
port => 5000,
stream => {
on_data => sub ($self, $bytes) {
...
},
},
);
host
host => '0.0.0.0'
The local address to bind.
For example:
'127.0.0.1'
listens only on the local IPv4 loopback interface, while:
'0.0.0.0'
requests all IPv4 interfaces.
IPv6 addresses may also be used.
port
port => 5000
The TCP port to bind.
Use zero to let the kernel select an available port:
port => 0
The selected port can then be read with:
my $port = $listener->port;
This is particularly useful in tests.
loop
loop => $loop
Attach the Listener to the Loop immediately.
The option is not required.
A Listener may instead be created detached:
my $listener = Linux::Event::IO::Sock::Listener->new(
host => '127.0.0.1',
port => 5000,
stream => { ... },
);
and attached later:
$loop->add($listener);
UNIX-DOMAIN LISTENERS
Use unix instead of host and port:
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
unix => '/run/my-service.sock',
stream => {
on_data => sub ($self, $bytes) {
...
},
},
);
This creates a Unix-domain SOCK_STREAM listener.
Linux::Event uses the same Listener and Stream APIs for TCP and Unix-domain connections.
THE STREAM RECIPE
The nested stream hash describes the Stream that should be created for every accepted connection.
The simplest form supplies callbacks directly:
stream => {
on_data => sub ($self, $bytes) {
$self->write($bytes);
},
}
The default Stream class is:
Linux::Event::IO::Sock::Stream
so a simple server does not need to define its own connection subclass.
The recipe may contain:
classStream callbacks
datatuningtls
Stream callbacks
Callbacks inside stream belong to the accepted connection:
stream => {
on_ready => sub ($self) {
...
},
on_data => sub ($self, $bytes) {
...
},
on_error => sub ($self, $error) {
...
},
on_close => sub ($self) {
...
},
}
The available Stream callbacks are:
on_data
on_message
on_messages
on_ready
on_transport_ready
on_drain
on_eof
on_error
on_close
See Linux::Event::IO::Sock::Stream for their behavior.
class
A server may use a Stream subclass for its accepted connections:
package ChatConnection;
use parent 'Linux::Event::IO::Sock::Stream';
use Linux::Event::Framer 'Delimiter', "\n";
sub on_message ($self, $message) {
...
}
package main;
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
host => '0.0.0.0',
port => 5000,
stream => {
class => 'ChatConnection',
},
);
This is useful when all connections share a protocol, framing rule, TLS defaults, socket policy, tuning, or callback methods.
Mixing subclass methods and callbacks
The Stream recipe may still provide callbacks when a Stream subclass is used:
stream => {
class => 'ChatConnection',
on_close => sub ($self) {
remove_connection($self);
},
}
A constructor-style callback in the recipe overrides the same-named subclass method for Streams created by that Listener.
This lets a reusable protocol class be combined with application-specific behavior.
data
stream => {
data => $value,
...
}
Set the initial data value for each accepted Stream.
The supplied value becomes the connection's application data.
WHEN A CONNECTION IS ACCEPTED
Linux::Event accepts the socket, creates the configured Stream object, attaches that Stream to the same Loop as the Listener, and prepares it for asynchronous I/O.
For a plain connection, on_ready follows when the Stream is ready for application use.
For a TLS connection, on_ready waits until the TLS handshake and verification have completed.
LISTENER CALLBACKS
The Listener itself also has callbacks.
These are different from callbacks inside the stream recipe.
on_accept
on_accept => sub ($self, $stream) {
say "Accepted a new connection";
}
Called after a new Stream has been created for an accepted socket.
The second argument is the actual Stream object representing that connection.
This is useful for tasks such as:
keeping a list of connected clients
assigning application identity to a new connection
logging connection activity
performing application-level setup that belongs to the server rather than the protocol class
For example:
my %clients;
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
host => '0.0.0.0',
port => 5000,
stream => {
on_data => sub ($self, $bytes) {
...
},
},
on_accept => sub ($self, $stream) {
$clients{$stream} = 1;
},
);
on_error
on_error => sub ($self, $error) {
warn "Listener error: $error\n";
}
Called when an asynchronous error belongs to the Listener itself.
This is separate from a Stream's on_error.
For example:
my $listener = Linux::Event::IO::Sock::Listener->new(
...
stream => {
on_error => sub ($self, $error) {
warn "Client connection error: $error\n";
},
},
on_error => sub ($self, $error) {
warn "Listening socket error: $error\n";
},
);
The inner on_error handles connection errors.
The outer on_error handles Listener errors.
Errors from on_accept
If on_accept dies, Linux::Event closes only the newly accepted connection.
The Listener remains alive.
The error is reported through the Listener's on_error callback.
USING A LISTENER SUBCLASS
Listener callbacks can also be methods:
package MyListener;
use parent 'Linux::Event::IO::Sock::Listener';
sub on_accept ($self, $stream) {
say "New client";
}
A constructor callback overrides the same-named method for that particular Listener.
For most applications, constructor callbacks are the simpler choice unless Listener behavior itself is reusable.
TLS SERVERS
TLS belongs inside the stream recipe because TLS is a property of each accepted connection.
For example:
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
host => '0.0.0.0',
port => 9443,
stream => {
class => 'ServerConnection',
tls => {
cert_file => '/etc/myapp/server-cert.pem',
key_file => '/etc/myapp/server-key.pem',
},
},
);
The Listener prepares reusable server TLS configuration once.
Each accepted Stream receives its own TLS connection state.
Application callbacks see plaintext rather than encrypted wire bytes.
A Stream class does not need to be a special TLS subclass merely because one Listener uses it with TLS.
For example, the same ServerConnection class could be used by:
port => 8080
without tls, and by:
port => 8443
with tls.
See Linux::Event::TLS for the complete TLS configuration.
STREAM TUNING FOR ACCEPTED CONNECTIONS
A Stream subclass may define its normal stream_tuning defaults.
A particular Listener can override those defaults for every connection it accepts:
stream => {
class => 'ServerConnection',
tuning => {
idle_timeout => 30,
high_watermark => 2_097_152,
low_watermark => 524_288,
},
}
These values apply to Streams created by this Listener.
An individual Stream may later change its mutable settings with:
$stream->tune(...);
The precedence is therefore:
Stream subclass defaults
then Listener stream tuning
then live Stream tune()
See Linux::Event::IO::Sock::Stream for all tuning options.
LISTENER ACCEPTANCE TUNING
Listener acceptance settings are top-level constructor options.
They belong alongside host, port, and stream. They do not go inside the Stream recipe and they do not use a separate tuning hash.
For example:
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
host => '0.0.0.0',
port => 9999,
backlog => 8_192,
max_accept_per_tick => 512,
reuseaddr => 1,
reuseport => 1,
stream => {
class => 'ServerConnection',
tuning => {
idle_timeout => 30,
high_watermark => 2_097_152,
},
},
);
In this example:
backlog
max_accept_per_tick
reuseaddr
reuseport
configure the Listener, while:
idle_timeout
high_watermark
configure each accepted Stream.
The following settings affect the listening socket itself rather than the Streams it creates.
Most applications should leave their defaults unchanged.
backlog
Default: 4,096.
backlog => 8192
Requested kernel listen backlog.
It must be a positive integer.
max_accept_per_tick
Default: 256.
max_accept_per_tick => 512
Maximum number of connections Linux::Event accepts during one readiness turn.
This exists for fairness.
A busy listening socket should not indefinitely prevent existing connections, timers, and other resources from running.
A value of zero means to continue accepting until the kernel reports that no more connections are immediately available.
Zero is required when edge-triggered acceptance is enabled.
edge_triggered
Default: false.
edge_triggered => 1
Use edge-triggered accept readiness.
This is an advanced option.
When enabled, max_accept_per_tick must be zero so the accept queue is drained until it would block.
reuseaddr
Default: true.
reuseaddr => 1
Controls SO_REUSEADDR for a Listener created by Linux::Event.
reuseport
Default: false.
reuseport => 1
Controls SO_REUSEPORT for a Listener created by Linux::Event.
v6only
For an IPv6 Listener:
v6only => 1
controls IPV6_V6ONLY.
When unspecified, the operating-system default is used.
bind_device
bind_device => 'eth0'
Bind an Internet Listener to a particular Linux network interface using SO_BINDTODEVICE.
This is normally unnecessary.
UNIX SOCKET FILE OPTIONS
Unix-domain listeners have several options relating to the filesystem socket path.
unlink
unlink => 1
Allow an existing socket path to be removed as part of Listener setup.
The default is false.
unlink_on_close
unlink_on_close => 1
Remove the owned Unix socket path when the Listener closes.
The default is true.
permissions
Set filesystem permissions for a newly created Unix-domain socket path.
ADOPTING AN EXISTING LISTENING SOCKET
A Listener can take an already-created listening socket:
my $listener = Linux::Event::IO::Sock::Listener->new(
loop => $loop,
fh => $socket,
stream => {
on_data => sub ($self, $bytes) {
...
},
},
);
This is useful when socket creation or activation is managed elsewhere.
owns_socket controls whether the Listener owns the adopted socket's lifecycle.
PAUSING AND RESUMING ACCEPTANCE
pause
$listener->pause;
Temporarily stop accepting new connections while keeping the listening socket open.
Existing accepted Streams continue operating normally.
resume
$listener->resume;
Resume accepting new connections.
This can be useful when the application intentionally wants to limit admission without shutting down the server.
CLOSING A LISTENER
close
$listener->close;
Stop listening and end the Listener's ownership of the socket.
Existing accepted Streams are separate resources and are not automatically closed merely because the Listener closes.
detach
my $fh = $listener->detach;
Remove the listening socket from Linux::Event and return the still-open socket handle.
Detachment is terminal for the Listener object.
INFORMATION METHODS
port
my $port = $listener->port;
Return the bound TCP port.
This is especially useful when the Listener was created with:
port => 0
and the kernel selected the actual port.
family
Return the socket family in descriptive form.
family_number
Return the numeric socket family.
is_tcp
Return true for an Internet TCP Listener.
is_unix
Return true for a Unix-domain Listener.
state
Return the Listener's current lifecycle state.
Possible states include:
unattached
listening
paused
closed
failed
detached
RESOURCE EXHAUSTION
If the process temporarily runs out of resources while accepting connections, Linux::Event pauses acceptance before reporting the error.
This prevents a busy readable listening socket from repeatedly generating the same failure in a tight loop.
The failure is then delivered through the Listener's on_error callback.
PERFORMANCE MODEL
The Stream recipe is prepared when the Listener is constructed.
Linux::Event does not rebuild the Stream class, callback, TLS, and tuning configuration from scratch every time a connection is accepted.
This allows accepted connections to use the same convenient callback and subclass APIs without adding repeated configuration work to the accept path.
SEE ALSO
Linux::Event, Linux::Event::Loop, Linux::Event::IO::Sock::Stream, Linux::Event::TLS, Linux::Event::Error, docs/SOCKET-CONNECTIONS.md, docs/SOCKET-CONFIGURATION.md.