1POE::Wheel::SocketFactoUrsye(r3)Contributed Perl DocumenPtOaEt:i:oWnheel::SocketFactory(3)
2
3
4
6 POE::Wheel::SocketFactory - non-blocking socket creation
7
9 See "SYNOPSIS" in POE::Component::Server::TCP for a much simpler
10 version of this program.
11
12 #!perl
13
14 use warnings;
15 use strict;
16
17 use IO::Socket;
18 use POE qw(Wheel::SocketFactory Wheel::ReadWrite);
19
20 POE::Session->create(
21 inline_states => {
22 _start => sub {
23 # Start the server.
24 $_[HEAP]{server} = POE::Wheel::SocketFactory->new(
25 BindPort => 12345,
26 SuccessEvent => "on_client_accept",
27 FailureEvent => "on_server_error",
28 );
29 },
30 on_client_accept => sub {
31 # Begin interacting with the client.
32 my $client_socket = $_[ARG0];
33 my $io_wheel = POE::Wheel::ReadWrite->new(
34 Handle => $client_socket,
35 InputEvent => "on_client_input",
36 ErrorEvent => "on_client_error",
37 );
38 $_[HEAP]{client}{ $io_wheel->ID() } = $io_wheel;
39 },
40 on_server_error => sub {
41 # Shut down server.
42 my ($operation, $errnum, $errstr) = @_[ARG0, ARG1, ARG2];
43 warn "Server $operation error $errnum: $errstr\n";
44 delete $_[HEAP]{server};
45 },
46 on_client_input => sub {
47 # Handle client input.
48 my ($input, $wheel_id) = @_[ARG0, ARG1];
49 $input =~ tr[a-zA-Z][n-za-mN-ZA-M]; # ASCII rot13
50 $_[HEAP]{client}{$wheel_id}->put($input);
51 },
52 on_client_error => sub {
53 # Handle client error, including disconnect.
54 my $wheel_id = $_[ARG3];
55 delete $_[HEAP]{client}{$wheel_id};
56 },
57 }
58 );
59
60 POE::Kernel->run();
61 exit;
62
64 POE::Wheel::SocketFactory creates sockets upon demand. It can create
65 connectionless UDP sockets, but it really shines for client/server work
66 where establishing connections normally would block.
67
69 new
70 new() creates a new POE::Wheel::SocketFactory object. For sockets
71 which listen() for and accept() connections, the wheel will generate
72 new sockets for each accepted client. Socket factories for one-shot
73 sockets, such as UDP peers or clients established by connect() only
74 emit a single socket and can be destroyed afterwards without ill
75 effects.
76
77 new() always returns a POE::Wheel::SocketFactory object even if it
78 fails to establish the socket. This allows the object to be queried
79 after it has sent its session a "FailureEvent".
80
81 new() accepts a healthy number of named parameters, each governing some
82 aspect of socket creation.
83
84 Creating the Socket
85
86 Socket creation is done with Perl's built-in socket() function. The
87 new() parameters beginning with "Socket" determine how socket() will be
88 called.
89
90 SocketDomain
91
92 "SocketDomain" instructs the wheel to create a socket within a
93 particular domain. Supported domains are "AF_UNIX", "AF_INET",
94 "AF_INET6", "PF_UNIX", "PF_INET", and "PF_INET6". If omitted, the
95 socket will be created in the "AF_INET" domain.
96
97 POE::Wheel::SocketFactory contains a table of supported domains and the
98 instructions needed to create them. Please send patches to support
99 additional domains, as needed.
100
101 Note: "AF_INET6" and "PF_INET6" are supplied by the Socket module
102 included in Perl 5.8.0 or later. Perl versions before 5.8.0 should not
103 attempt to use IPv6 until someone contributes a workaround.
104
105 IPv6 support requires a Socket module that implements getaddrinfo() and
106 unpack_sockaddr_in6(). There may be other modules that perform these
107 functions, but most if not all of them have been deprecated with the
108 advent of proper core Socket support for IPv6.
109
110 SocketType
111
112 "SocketType" supplies the socket() call with a particular socket type,
113 which may be "SOCK_STREAM" or "SOCK_DGRAM". "SOCK_STREAM" is the
114 default if "SocketType" is not supplied.
115
116 SocketProtocol
117
118 "SocketProtocol" sets the socket() call's protocol. Protocols may be
119 specified by number or name. "SocketProtocol" is ignored for UNIX
120 domain sockets.
121
122 The protocol defaults to "tcp" for INET domain sockets. There is no
123 default for other socket domains.
124
125 Setting Socket Options
126
127 POE::Wheel::SocketFactory uses ioctl(), fcntl() and setsockopt() to set
128 socket options after the socket is created. All sockets are set non-
129 blocking, and bound sockets may be made reusable.
130
131 Reuse
132
133 When set, the "Reuse" parameter allows a bound port to be reused
134 immediately. "Reuse" is considered enabled if it contains "yes", "on",
135 or a true numeric value. All other values disable port reuse, as does
136 omitting "Reuse" entirely.
137
138 For security purposes, a port cannot be reused for a minute or more
139 after a server has released it. This gives clients time to realize the
140 port has been abandoned. Otherwise a malicious service may snatch up
141 the port and spoof the legitimate service.
142
143 It's also terribly annoying to wait a minute or more between server
144 invocations, especially during development.
145
146 Bind the Socket to an Address and Port
147
148 A socket may optionally be bound to a specific interface and port. The
149 "INADDR_ANY" address may be used to bind to a specific port across all
150 interfaces.
151
152 Sockets are bound using bind(). POE::Wheel::SocketFactory parameters
153 beginning with "Bind" control how bind() is called.
154
155 BindAddress
156
157 "BindAddress" sets an address to bind the socket's local endpoint to.
158 "INADDR_ANY" will be used if "BindAddress" is not specified.
159
160 "BindAddress" may contain either a string or a packed Internet address
161 (for "INET" domain sockets). The string parameter should be a dotted
162 numeric address or a resolvable host name. Note that the host name
163 will be resolved with a blocking call. If this is not desired, use
164 POE::Component::Client::DNS to perform a non-blocking name resolution.
165
166 When used to bind a "UNIX" domain socket, "BindAddress" should contain
167 a path describing the socket's filename. This is required for server
168 sockets and datagram client sockets. "BindAddress" has no default
169 value for UNIX sockets.
170
171 BindPort
172
173 "BindPort" is only meaningful for "INET" domain sockets. It contains a
174 port on the "BindAddress" interface where the socket will be bound. It
175 defaults to 0 if omitted, which will cause the bind() call to choose an
176 indeterminate unallocated port.
177
178 "BindPort" may be a port number or a name that can be looked up in the
179 system's services (or equivalent) database.
180
181 Connectionless Sockets
182
183 Connectionless sockets may interact with remote endpoints without
184 needing to listen() for connections or connect() to remote addresses.
185
186 This class of sockets is complete after the bind() call.
187
188 Connecting the Socket to a Remote Endpoint
189
190 A socket may either listen for connections to arrive, initiate
191 connections to a remote endpoint, or be connectionless (such as in the
192 case of UDP sockets).
193
194 POE::Wheel::SocketFactory will initiate a client connection when new()
195 is capped with parameters that describe a remote endpoint. In all
196 other cases, the socket will either listen for connections or be
197 connectionless depending on the socket type.
198
199 The following parameters describe a socket's remote endpoint. They
200 determine how POE::Wheel::SocketFactory will call Perl's built-in
201 connect() function.
202
203 RemoteAddress
204
205 "RemoteAddress" specifies the remote address to which a socket should
206 connect. If present, POE::Wheel::SocketFactory will create a client
207 socket that attempts to collect to the "RemoteAddress". Otherwise, if
208 the protocol warrants it, the wheel will create a listening socket and
209 attempt to accept connections.
210
211 As with the bind address, "RemoteAddress" may be a string containing a
212 dotted quad or a resolvable host name. It may also be a packed
213 Internet address, or a UNIX socket path. It will be packed, with or
214 without an accompanying "RemotePort", as necessary for the socket
215 domain.
216
217 RemotePort
218
219 "RemotePort" is the port to which the socket should connect. It is
220 required for "INET" client sockets, since the remote endpoint must
221 contain both an address and a port.
222
223 The remote port may be numeric, or it may be a symbolic name found in
224 /etc/services or the equivalent for your operating system.
225
226 Listening for Connections
227
228 Streaming sockets that have no remote endpoint are considered to be
229 server sockets. POE::Wheel::SocketFactory will listen() for
230 connections to these sockets, accept() the new clients, and send the
231 application events with the new client sockets.
232
233 POE::Wheel::SocketFactory constructor parameters beginning with
234 "Listen" control how the listen() function is called.
235
236 ListenQueue
237
238 "ListenQueue" specifies the length of the socket's listen() queue. It
239 defaults to "SOMAXCONN" if omitted. "ListenQueue" values greater than
240 "SOMAXCONN" will be clipped to "SOMAXCONN". Excessively large
241 "ListenQueue" values are not necessarily portable, and may cause errors
242 in some rare cases.
243
244 Emitting Events
245
246 POE::Wheel::SocketFactory emits a small number of events depending on
247 what happens during socket setup or while listening for new
248 connections.
249
250 See "PUBLIC EVENTS" for more details.
251
252 SuccessEvent
253
254 "SuccessEvent" names the event that will be emitted whenever
255 POE::Wheel::SocketFactory succeeds in creating a new socket.
256
257 For connectionless sockets, "SuccessEvent" happens just after the
258 socket is created.
259
260 For client connections, "SuccessEvent" is fired when the connection has
261 successfully been established with the remote endpoint.
262
263 Server sockets emit a "SuccessEvent" for every successfully accepted
264 client.
265
266 FailureEvent
267
268 "FailureEvent" names the event POE::Wheel::SocketFactory will emit
269 whenever something goes wrong. It usually represents some kind of
270 built-in function call error. See "PUBLIC EVENTS" for details, as some
271 errors are handled internally by this wheel.
272
273 event
274 event() allows a session to change the events emitted by a wheel
275 without destroying and re-creating the wheel. It accepts one or more
276 of the events listed in "PUBLIC EVENTS". Undefined event names disable
277 those events.
278
279 event() is described in more depth in POE::Wheel.
280
281 getsockname
282 getsockname() behaves like the built-in function of the same name. It
283 returns the local endpoint information for POE::Wheel::SocketFactory's
284 encapsulated listening socket.
285
286 getsockname() allows applications to determine the address and port to
287 which POE::Wheel::SocketFactory has bound its listening socket.
288
289 Test applications may use getsockname() to find the server socket after
290 POE::Wheel::SocketFactory has bound to INADDR_ANY port 0.
291
292 Since there is no event fired immediately after a successful creation
293 of a listening socket, applications can use getsockname() to verify
294 this.
295
296 use Socket 'unpack_sockaddr_in';
297
298 my $listener = POE::Wheel::SocketFactory->new(
299 BindPort => 123,
300 SuccessEvent => 'got_client',
301 FailureEvent => 'listener_failed',
302 Reuse => 'on',
303 );
304
305 my ($port, $addr) = unpack_sockaddr_in($listener->getsockname);
306 print "Socket successfully bound\n" if $port;
307
308 ID
309 ID() returns the wheel's unique ID. The ID will also be included in
310 every event the wheel generates. Applications can match events back to
311 the objects that generated them.
312
313 pause_accept
314 Applications may occasionally need to block incoming connections.
315 pause_accept() pauses the event watcher that triggers accept(). New
316 inbound connections will stack up in the socket's listen() queue until
317 the queue overflows or the application calls resume_accept().
318
319 Pausing accept() can limit the amount of load a server generates. It's
320 also useful in pre-forking servers when the master process shouldn't
321 accept connections at all.
322
323 pause_accept() and resume_accept() is quicker and more reliable than
324 dynamically destroying and re-creating a POE::Wheel::SocketFactory
325 object.
326
327 resume_accept
328 resume_accept() resumes the watcher that triggers accept(). See
329 "pause_accept" for a more detailed discussion.
330
332 POE::Wheel::SocketFactory emits two public events.
333
334 SuccessEvent
335 "SuccessEvent" names an event that will be sent to the creating session
336 whenever a POE::Wheel::SocketFactory has created a new socket. For
337 connectionless sockets, it's when the socket is created. For
338 connecting clients, it's after the connection has been established.
339 And for listening servers, "SuccessEvent" is fired after each new
340 client is accepted.
341
342 Common SuccessEvent Parameters
343
344 In all cases, $_[ARG0] holds the new socket's filehandle, and $_[ARG3]
345 contains the POE::Wheel::SocketFactory's ID. Other parameters vary
346 depending on the socket's domain and whether it's listening or
347 connecting. See below for the differences.
348
349 INET SuccessEvent Parameters
350
351 For INET sockets, $_[ARG1] and $_[ARG2] hold the socket's remote
352 address and port, respectively. The address is packed; see "inet_ntop"
353 in Socket if a human-readable address is needed.
354
355 sub handle_new_client {
356 my $accepted_socket = $_[ARG0];
357
358 my $peer_host = inet_ntop(
359 ((length($_[ARG1]) == 4) ? AF_INET : AF_INET6),
360 $_[ARG1]
361 );
362
363 print(
364 "Wheel $_[ARG3] accepted a connection from ",
365 "$peer_host port $peer_port\n"
366 );
367
368 spawn_connection_session($accepted_handle);
369 }
370
371 UNIX Client SuccessEvent Parameters
372
373 For UNIX client sockets, $_[ARG1] often (but not always) holds the
374 server address. Some systems cannot retrieve a UNIX socket's remote
375 address. $_[ARG2] is always undef for UNIX client sockets.
376
377 UNIX Server SuccessEvent Parameters
378
379 According to Perl Cookbook, the remote address returned by accept() on
380 UNIX sockets is undefined, so $_[ARG1] and $_[ARG2] are also undefined
381 in this case.
382
383 FailureEvent
384 "FailureEvent" names the event that will be emitted when a socket error
385 occurs. POE::Wheel::SocketFactory handles "EAGAIN" internally, so it
386 doesn't count as an error.
387
388 "FailureEvent" events include the standard error event parameters:
389
390 $_[ARG0] describes which part of socket creation failed. It often
391 holds a Perl built-in function name.
392
393 $_[ARG1] and $_[ARG2] describe how the operation failed. They contain
394 the numeric and stringified versions of $!, respectively. An
395 application cannot merely check the global $! variable since it may
396 change during event dispatch.
397
398 Finally, $_[ARG3] contains the ID for the POE::Wheel::SocketFactory
399 instance that generated the event. See "ID" and "ID" in POE::Wheel for
400 uses for wheel IDs.
401
402 A sample FailureEvent handler:
403
404 sub handle_failure {
405 my ($operation, $errnum, $errstr, $wheel_id) = @_[ARG0..ARG3];
406 warn "Wheel $wheel_id generated $operation error $errnum: $errstr\n";
407 delete $_[HEAP]{wheels}{$wheel_id}; # shut down that wheel
408 }
409
411 POE::Wheel describes the basic operations of all wheels in more depth.
412 You need to know this.
413
414 Socket::GetAddrInfo is required for IPv6 work.
415 POE::Wheel::SocketFactory will load it automatically if it's installed.
416 SocketDomain => AF_INET6 is required to trigger IPv6 behaviors.
417 AF_INET6 is exported by the Socket module on all but the oldest
418 versions of Perl 5. If your Socket doesn't provide AF_INET6, try
419 installing Socket6 instead.
420
421 The SEE ALSO section in POE contains a table of contents covering the
422 entire POE distribution.
423
425 Many (if not all) of the croak/carp/warn/die statements should fire
426 back "FailureEvent" instead.
427
428 SocketFactory is only tested with UNIX streams and INET sockets using
429 the UDP and TCP protocols. Others should work after the module's
430 internal configuration tables are updated. Please send patches.
431
433 Please see POE for more information about authors and contributors.
434
435
436
437perl v5.36.0 2023-01-20 POE::Wheel::SocketFactory(3)