---
name: "POE::Wheel::SocketFactory"
section: "3pm"
platform: "linux"
package: "perl-poe"
version: "1.370-2"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/POE::Wheel::SocketFactory"
---

# POE::Wheel::SocketFactory(3pm)

non-blocking socket creation

## NAME

POE::Wheel::SocketFactory - non-blocking socket creation

## SYNOPSIS

See "SYNOPSIS" in POE::Component::Server::TCP for a much simpler version of this program.

```
  #!perl
  use warnings;
  use strict;
  use IO::Socket;
  use POE qw(Wheel::SocketFactory Wheel::ReadWrite);
  POE::Session->create(
    inline_states => {
      _start => sub {
        # Start the server.
        $_[HEAP]{server} = POE::Wheel::SocketFactory->new(
          BindPort => 12345,
          SuccessEvent => "on_client_accept",
          FailureEvent => "on_server_error",
        );
      },
      on_client_accept => sub {
        # Begin interacting with the client.
        my $client_socket = $_[ARG0];
        my $io_wheel = POE::Wheel::ReadWrite->new(
          Handle => $client_socket,
          InputEvent => "on_client_input",
          ErrorEvent => "on_client_error",
        );
        $_[HEAP]{client}{ $io_wheel->ID() } = $io_wheel;
      },
      on_server_error => sub {
        # Shut down server.
        my ($operation, $errnum, $errstr) = @_[ARG0, ARG1, ARG2];
        warn "Server $operation error $errnum: $errstr\n";
        delete $_[HEAP]{server};
      },
      on_client_input => sub {
        # Handle client input.
        my ($input, $wheel_id) = @_[ARG0, ARG1];
        $input =~ tr[a-zA-Z][n-za-mN-ZA-M]; # ASCII rot13
        $_[HEAP]{client}{$wheel_id}->put($input);
      },
      on_client_error => sub {
        # Handle client error, including disconnect.
        my $wheel_id = $_[ARG3];
        delete $_[HEAP]{client}{$wheel_id};
      },
    }
  );
  POE::Kernel->run();
  exit;
```

## DESCRIPTION

POE::Wheel::SocketFactory creates sockets upon demand.  It can create connectionless UDP sockets, but it really shines for client/server work where establishing connections normally would block.

## PUBLIC METHODS

### new

**new()** creates a new POE::Wheel::SocketFactory object.  For sockets which **listen()** for and **accept()** connections, the wheel will generate new sockets for each accepted client.  Socket factories for one-shot sockets, such as UDP peers or clients established by **connect()** only emit a single socket and can be destroyed afterwards without ill effects.

**new()** always returns a POE::Wheel::SocketFactory object even if it fails to establish the socket.  This allows the object to be queried after it has sent its session a `"FailureEvent"`.

**new()** accepts a healthy number of named parameters, each governing some aspect of socket creation.

*Creating the Socket*

Socket creation is done with Perl's built-in **socket()** function.  The **new()** parameters beginning with `"Socket"` determine how **socket()** will be called.

SocketDomain

`"SocketDomain"` instructs the wheel to create a socket within a particular domain.  Supported domains are `"AF_UNIX"`, `"AF_INET"`, `"AF_INET6"`, `"PF_UNIX"`, `"PF_INET"`, and `"PF_INET6"`.  If omitted, the socket will be created in the `"AF_INET"` domain.

POE::Wheel::SocketFactory contains a table of supported domains and the instructions needed to create them.  Please send patches to support additional domains, as needed.

Note: `"AF_INET6"` and `"PF_INET6"` are supplied by the Socket module included in Perl 5.8.0 or later.  Perl versions before 5.8.0 should not attempt to use IPv6 until someone contributes a workaround.

IPv6 support requires a Socket module that implements **getaddrinfo()** and **unpack\_sockaddr\_in6()**.  There may be other modules that perform these functions, but most if not all of them have been deprecated with the advent of proper core Socket support for IPv6.

SocketType

`"SocketType"` supplies the **socket()** call with a particular socket type, which may be `"SOCK_STREAM"` or `"SOCK_DGRAM"`.  `"SOCK_STREAM"` is the default if `"SocketType"` is not supplied.

SocketProtocol

`"SocketProtocol"` sets the **socket()** call's protocol.  Protocols may be specified by number or name.  `"SocketProtocol"` is ignored for UNIX domain sockets.

The protocol defaults to "tcp" for INET domain sockets.  There is no default for other socket domains.

*Setting Socket Options*

POE::Wheel::SocketFactory uses **ioctl()**, **fcntl()** and **setsockopt()** to set socket options after the socket is created.  All sockets are set non-blocking, and bound sockets may be made reusable.

Reuse

When set, the `"Reuse"` parameter allows a bound port to be reused immediately.  `"Reuse"` is considered enabled if it contains "yes", "on", or a true numeric value.  All other values disable port reuse, as does omitting `"Reuse"` entirely.

For security purposes, a port cannot be reused for a minute or more after a server has released it.  This gives clients time to realize the port has been abandoned.  Otherwise a malicious service may snatch up the port and spoof the legitimate service.

It's also terribly annoying to wait a minute or more between server invocations, especially during development.

*Bind the Socket to an Address and Port*

A socket may optionally be bound to a specific interface and port. The `"INADDR_ANY"` address may be used to bind to a specific port across all interfaces.

Sockets are bound using **bind()**.  POE::Wheel::SocketFactory parameters beginning with `"Bind"` control how **bind()** is called.

BindAddress

`"BindAddress"` sets an address to bind the socket's local endpoint to. `"INADDR_ANY"` will be used if `"BindAddress"` is not specified.

`"BindAddress"` may contain either a string or a packed Internet address (for "INET" domain sockets).  The string parameter should be a dotted numeric address or a resolvable host name.  Note that the host name will be resolved with a blocking call.  If this is not desired, use POE::Component::Client::DNS to perform a non-blocking name resolution.

When used to bind a "UNIX" domain socket, `"BindAddress"` should contain a path describing the socket's filename.  This is required for server sockets and datagram client sockets.  `"BindAddress"` has no default value for UNIX sockets.

BindPort

`"BindPort"` is only meaningful for "INET" domain sockets.  It contains a port on the `"BindAddress"` interface where the socket will be bound. It defaults to 0 if omitted, which will cause the **bind()** call to choose an indeterminate unallocated port.

`"BindPort"` may be a port number or a name that can be looked up in the system's services (or equivalent) database.

*Connectionless Sockets*

Connectionless sockets may interact with remote endpoints without needing to **listen()** for connections or **connect()** to remote addresses.

This class of sockets is complete after the **bind()** call.

*Connecting the Socket to a Remote Endpoint*

A socket may either listen for connections to arrive, initiate connections to a remote endpoint, or be connectionless (such as in the case of UDP sockets).

POE::Wheel::SocketFactory will initiate a client connection when **new()** is capped with parameters that describe a remote endpoint.  In all other cases, the socket will either listen for connections or be connectionless depending on the socket type.

The following parameters describe a socket's remote endpoint.  They determine how POE::Wheel::SocketFactory will call Perl's built-in **connect()** function.

RemoteAddress

`"RemoteAddress"` specifies the remote address to which a socket should connect.  If present, POE::Wheel::SocketFactory will create a client socket that attempts to collect to the `"RemoteAddress"`.  Otherwise, if the protocol warrants it, the wheel will create a listening socket and attempt to accept connections.

As with the bind address, `"RemoteAddress"` may be a string containing a dotted quad or a resolvable host name.  It may also be a packed Internet address, or a UNIX socket path.  It will be packed, with or without an accompanying `"RemotePort"`, as necessary for the socket domain.

RemotePort

`"RemotePort"` is the port to which the socket should connect.  It is required for "INET" client sockets, since the remote endpoint must contain both an address and a port.

The remote port may be numeric, or it may be a symbolic name found in /etc/services or the equivalent for your operating system.

*Listening for Connections*

Streaming sockets that have no remote endpoint are considered to be server sockets.  POE::Wheel::SocketFactory will **listen()** for connections to these sockets, **accept()** the new clients, and send the application events with the new client sockets.

POE::Wheel::SocketFactory constructor parameters beginning with `"Listen"` control how the **listen()** function is called.

ListenQueue

`"ListenQueue"` specifies the length of the socket's **listen()** queue. It defaults to `"SOMAXCONN"` if omitted.  `"ListenQueue"` values greater than `"SOMAXCONN"` will be clipped to `"SOMAXCONN"`.  Excessively large `"ListenQueue"` values are not necessarily portable, and may cause errors in some rare cases.

*Emitting Events*

POE::Wheel::SocketFactory emits a small number of events depending on what happens during socket setup or while listening for new connections.

See "PUBLIC EVENTS" for more details.

SuccessEvent

`"SuccessEvent"` names the event that will be emitted whenever POE::Wheel::SocketFactory succeeds in creating a new socket.

For connectionless sockets, `"SuccessEvent"` happens just after the socket is created.

For client connections, `"SuccessEvent"` is fired when the connection has successfully been established with the remote endpoint.

Server sockets emit a `"SuccessEvent"` for every successfully accepted client.

FailureEvent

`"FailureEvent"` names the event POE::Wheel::SocketFactory will emit whenever something goes wrong.  It usually represents some kind of built-in function call error.  See "PUBLIC EVENTS" for details, as some errors are handled internally by this wheel.

### event

**event()** allows a session to change the events emitted by a wheel without destroying and re-creating the wheel.  It accepts one or more of the events listed in "PUBLIC EVENTS".  Undefined event names disable those events.

**event()** is described in more depth in POE::Wheel.

### getsockname

**getsockname()** behaves like the built-in function of the same name.  It returns the local endpoint information for POE::Wheel::SocketFactory's encapsulated listening socket.

**getsockname()** allows applications to determine the address and port to which POE::Wheel::SocketFactory has bound its listening socket.

Test applications may use **getsockname()** to find the server socket after POE::Wheel::SocketFactory has bound to INADDR\_ANY port 0.

Since there is no event fired immediately after a successful creation of a listening socket, applications can use **getsockname()** to verify this.

```
 use Socket 'unpack_sockaddr_in';
 my $listener = POE::Wheel::SocketFactory->new(
     BindPort     => 123,
     SuccessEvent => 'got_client',
     FailureEvent => 'listener_failed',
     Reuse        => 'on',
 );
 my ($port, $addr) = unpack_sockaddr_in($listener->getsockname);
 print "Socket successfully bound\n" if $port;
```

### ID

**ID()** returns the wheel's unique ID.  The ID will also be included in every event the wheel generates.  Applications can match events back to the objects that generated them.

### pause\_accept

Applications may occasionally need to block incoming connections. **pause\_accept()** pauses the event watcher that triggers **accept()**.  New inbound connections will stack up in the socket's **listen()** queue until the queue overflows or the application calls **resume\_accept()**.

Pausing **accept()** can limit the amount of load a server generates. It's also useful in pre-forking servers when the master process shouldn't accept connections at all.

**pause\_accept()** and **resume\_accept()** is quicker and more reliable than dynamically destroying and re-creating a POE::Wheel::SocketFactory object.

### resume\_accept

**resume\_accept()** resumes the watcher that triggers **accept()**.  See "pause\_accept" for a more detailed discussion.

## PUBLIC EVENTS

POE::Wheel::SocketFactory emits two public events.

### SuccessEvent

`"SuccessEvent"` names an event that will be sent to the creating session whenever a POE::Wheel::SocketFactory has created a new socket. For connectionless sockets, it's when the socket is created.  For connecting clients, it's after the connection has been established. And for listening servers, `"SuccessEvent"` is fired after each new client is accepted.

*Common SuccessEvent Parameters*

In all cases, `$_[ARG0]` holds the new socket's filehandle, and `$_[ARG3]` contains the POE::Wheel::SocketFactory's ID.  Other parameters vary depending on the socket's domain and whether it's listening or connecting.  See below for the differences.

*INET SuccessEvent Parameters*

For INET sockets, `$_[ARG1]` and `$_[ARG2]` hold the socket's remote address and port, respectively.  The address is packed; see "inet\_ntop" in Socket if a human-readable address is needed.

```
  sub handle_new_client {
    my $accepted_socket = $_[ARG0];
    my $peer_host = inet_ntop(
      ((length($_[ARG1]) == 4) ? AF_INET : AF_INET6),
      $_[ARG1]
    );
    print(
      "Wheel $_[ARG3] accepted a connection from ",
      "$peer_host port $peer_port\n"
    );
    spawn_connection_session($accepted_handle);
  }
```

*UNIX Client SuccessEvent Parameters*

For UNIX client sockets, `$_[ARG1]` often (but not always) holds the server address.  Some systems cannot retrieve a UNIX socket's remote address.  `$_[ARG2]` is always undef for UNIX client sockets.

*UNIX Server SuccessEvent Parameters*

According to *Perl Cookbook*, the remote address returned by **accept()** on UNIX sockets is undefined, so `$_[ARG1]` and `$_[ARG2]` are also undefined in this case.

### FailureEvent

`"FailureEvent"` names the event that will be emitted when a socket error occurs.  POE::Wheel::SocketFactory handles `"EAGAIN"` internally, so it doesn't count as an error.

`"FailureEvent"` events include the standard error event parameters:

`$_[ARG0]` describes which part of socket creation failed.  It often holds a Perl built-in function name.

`$_[ARG1]` and `$_[ARG2]` describe how the operation failed.  They contain the numeric and stringified versions of `$!`, respectively. An application cannot merely check the global `$!` variable since it may change during event dispatch.

Finally, `$_[ARG3]` contains the ID for the POE::Wheel::SocketFactory instance that generated the event.  See "ID" and "ID" in POE::Wheel for uses for wheel IDs.

A sample FailureEvent handler:

```
  sub handle_failure {
    my ($operation, $errnum, $errstr, $wheel_id) = @_[ARG0..ARG3];
    warn "Wheel $wheel_id generated $operation error $errnum: $errstr\n";
    delete $_[HEAP]{wheels}{$wheel_id}; # shut down that wheel
  }
```

## SEE ALSO

POE::Wheel describes the basic operations of all wheels in more depth.  You need to know this.

Socket::GetAddrInfo is required for IPv6 work. POE::Wheel::SocketFactory will load it automatically if it's installed.  SocketDomain =\> AF\_INET6 is required to trigger IPv6 behaviors.  AF\_INET6 is exported by the Socket module on all but the oldest versions of Perl 5.  If your Socket doesn't provide AF\_INET6, try installing Socket6 instead.

The SEE ALSO section in POE contains a table of contents covering the entire POE distribution.

## BUGS

Many (if not all) of the croak/carp/warn/die statements should fire back `"FailureEvent"` instead.

SocketFactory is only tested with UNIX streams and INET sockets using the UDP and TCP protocols.  Others should work after the module's internal configuration tables are updated.  Please send patches.

## AUTHORS & COPYRIGHTS

Please see POE for more information about authors and contributors.
