Subversion Repositories qbpwcf-lib(archive)

Rev

Rev 915 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 liveuser 1
# Socket
2
 
3
[![Build Status](https://travis-ci.org/reactphp/socket.svg?branch=master)](https://travis-ci.org/reactphp/socket)
4
 
5
Async, streaming plaintext TCP/IP and secure TLS socket server and client
6
connections for [ReactPHP](https://reactphp.org/).
7
 
8
The socket library provides re-usable interfaces for a socket-layer
9
server and client based on the [`EventLoop`](https://github.com/reactphp/event-loop)
10
and [`Stream`](https://github.com/reactphp/stream) components.
11
Its server component allows you to build networking servers that accept incoming
12
connections from networking clients (such as an HTTP server).
13
Its client component allows you to build networking clients that establish
14
outgoing connections to networking servers (such as an HTTP or database client).
15
This library provides async, streaming means for all of this, so you can
16
handle multiple concurrent connections without blocking.
17
 
18
**Table of Contents**
19
 
20
* [Quickstart example](#quickstart-example)
21
* [Connection usage](#connection-usage)
22
  * [ConnectionInterface](#connectioninterface)
23
    * [getRemoteAddress()](#getremoteaddress)
24
    * [getLocalAddress()](#getlocaladdress)
25
* [Server usage](#server-usage)
26
  * [ServerInterface](#serverinterface)
27
    * [connection event](#connection-event)
28
    * [error event](#error-event)
29
    * [getAddress()](#getaddress)
30
    * [pause()](#pause)
31
    * [resume()](#resume)
32
    * [close()](#close)
33
  * [Server](#server)
34
  * [Advanced server usage](#advanced-server-usage)
35
    * [TcpServer](#tcpserver)
36
    * [SecureServer](#secureserver)
37
    * [UnixServer](#unixserver)
38
    * [LimitingServer](#limitingserver)
39
      * [getConnections()](#getconnections)
40
* [Client usage](#client-usage)
41
  * [ConnectorInterface](#connectorinterface)
42
    * [connect()](#connect)
43
  * [Connector](#connector)
44
  * [Advanced client usage](#advanced-client-usage)
45
    * [TcpConnector](#tcpconnector)
46
    * [HappyEyeBallsConnector](#happyeyeballsconnector)
47
    * [DnsConnector](#dnsconnector)
48
    * [SecureConnector](#secureconnector)
49
    * [TimeoutConnector](#timeoutconnector)
50
    * [UnixConnector](#unixconnector)
51
    * [FixUriConnector](#fixeduriconnector)
52
* [Install](#install)
53
* [Tests](#tests)
54
* [License](#license)
55
 
56
## Quickstart example
57
 
58
Here is a server that closes the connection if you send it anything:
59
 
60
```php
61
$loop = React\EventLoop\Factory::create();
62
$socket = new React\Socket\Server('127.0.0.1:8080', $loop);
63
 
64
$socket->on('connection', function (React\Socket\ConnectionInterface $connection) {
65
    $connection->write("Hello " . $connection->getRemoteAddress() . "!\n");
66
    $connection->write("Welcome to this amazing server!\n");
67
    $connection->write("Here's a tip: don't say anything.\n");
68
 
69
    $connection->on('data', function ($data) use ($connection) {
70
        $connection->close();
71
    });
72
});
73
 
74
$loop->run();
75
```
76
 
77
See also the [examples](examples).
78
 
79
Here's a client that outputs the output of said server and then attempts to
80
send it a string:
81
 
82
```php
83
$loop = React\EventLoop\Factory::create();
84
$connector = new React\Socket\Connector($loop);
85
 
86
$connector->connect('127.0.0.1:8080')->then(function (React\Socket\ConnectionInterface $connection) use ($loop) {
87
    $connection->pipe(new React\Stream\WritableResourceStream(STDOUT, $loop));
88
    $connection->write("Hello World!\n");
89
});
90
 
91
$loop->run();
92
```
93
 
94
## Connection usage
95
 
96
### ConnectionInterface
97
 
98
The `ConnectionInterface` is used to represent any incoming and outgoing
99
connection, such as a normal TCP/IP connection.
100
 
101
An incoming or outgoing connection is a duplex stream (both readable and
102
writable) that implements React's
103
[`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface).
104
It contains additional properties for the local and remote address (client IP)
105
where this connection has been established to/from.
106
 
107
Most commonly, instances implementing this `ConnectionInterface` are emitted
108
by all classes implementing the [`ServerInterface`](#serverinterface) and
109
used by all classes implementing the [`ConnectorInterface`](#connectorinterface).
110
 
111
Because the `ConnectionInterface` implements the underlying
112
[`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface)
113
you can use any of its events and methods as usual:
114
 
115
```php
116
$connection->on('data', function ($chunk) {
117
    echo $chunk;
118
});
119
 
120
$connection->on('end', function () {
121
    echo 'ended';
122
});
123
 
124
$connection->on('error', function (Exception $e) {
125
    echo 'error: ' . $e->getMessage();
126
});
127
 
128
$connection->on('close', function () {
129
    echo 'closed';
130
});
131
 
132
$connection->write($data);
133
$connection->end($data = null);
134
$connection->close();
135
// …
136
```
137
 
138
For more details, see the
139
[`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface).
140
 
141
#### getRemoteAddress()
142
 
143
The `getRemoteAddress(): ?string` method returns the full remote address
144
(URI) where this connection has been established with.
145
 
146
```php
147
$address = $connection->getRemoteAddress();
148
echo 'Connection with ' . $address . PHP_EOL;
149
```
150
 
151
If the remote address can not be determined or is unknown at this time (such as
152
after the connection has been closed), it MAY return a `NULL` value instead.
153
 
154
Otherwise, it will return the full address (URI) as a string value, such
155
as `tcp://127.0.0.1:8080`, `tcp://[::1]:80`, `tls://127.0.0.1:443`,
156
`unix://example.sock` or `unix:///path/to/example.sock`.
157
Note that individual URI components are application specific and depend
158
on the underlying transport protocol.
159
 
160
If this is a TCP/IP based connection and you only want the remote IP, you may
161
use something like this:
162
 
163
```php
164
$address = $connection->getRemoteAddress();
165
$ip = trim(parse_url($address, PHP_URL_HOST), '[]');
166
echo 'Connection with ' . $ip . PHP_EOL;
167
```
168
 
169
#### getLocalAddress()
170
 
171
The `getLocalAddress(): ?string` method returns the full local address
172
(URI) where this connection has been established with.
173
 
174
```php
175
$address = $connection->getLocalAddress();
176
echo 'Connection with ' . $address . PHP_EOL;
177
```
178
 
179
If the local address can not be determined or is unknown at this time (such as
180
after the connection has been closed), it MAY return a `NULL` value instead.
181
 
182
Otherwise, it will return the full address (URI) as a string value, such
183
as `tcp://127.0.0.1:8080`, `tcp://[::1]:80`, `tls://127.0.0.1:443`,
184
`unix://example.sock` or `unix:///path/to/example.sock`.
185
Note that individual URI components are application specific and depend
186
on the underlying transport protocol.
187
 
188
This method complements the [`getRemoteAddress()`](#getremoteaddress) method,
189
so they should not be confused.
190
 
191
If your `TcpServer` instance is listening on multiple interfaces (e.g. using
192
the address `0.0.0.0`), you can use this method to find out which interface
193
actually accepted this connection (such as a public or local interface).
194
 
195
If your system has multiple interfaces (e.g. a WAN and a LAN interface),
196
you can use this method to find out which interface was actually
197
used for this connection.
198
 
199
## Server usage
200
 
201
### ServerInterface
202
 
203
The `ServerInterface` is responsible for providing an interface for accepting
204
incoming streaming connections, such as a normal TCP/IP connection.
205
 
206
Most higher-level components (such as a HTTP server) accept an instance
207
implementing this interface to accept incoming streaming connections.
208
This is usually done via dependency injection, so it's fairly simple to actually
209
swap this implementation against any other implementation of this interface.
210
This means that you SHOULD typehint against this interface instead of a concrete
211
implementation of this interface.
212
 
213
Besides defining a few methods, this interface also implements the
214
[`EventEmitterInterface`](https://github.com/igorw/evenement)
215
which allows you to react to certain events.
216
 
217
#### connection event
218
 
219
The `connection` event will be emitted whenever a new connection has been
220
established, i.e. a new client connects to this server socket:
221
 
222
```php
223
$server->on('connection', function (React\Socket\ConnectionInterface $connection) {
224
    echo 'new connection' . PHP_EOL;
225
});
226
```
227
 
228
See also the [`ConnectionInterface`](#connectioninterface) for more details
229
about handling the incoming connection.
230
 
231
#### error event
232
 
233
The `error` event will be emitted whenever there's an error accepting a new
234
connection from a client.
235
 
236
```php
237
$server->on('error', function (Exception $e) {
238
    echo 'error: ' . $e->getMessage() . PHP_EOL;
239
});
240
```
241
 
242
Note that this is not a fatal error event, i.e. the server keeps listening for
243
new connections even after this event.
244
 
245
 
246
#### getAddress()
247
 
248
The `getAddress(): ?string` method can be used to
249
return the full address (URI) this server is currently listening on.
250
 
251
```php
252
$address = $server->getAddress();
253
echo 'Server listening on ' . $address . PHP_EOL;
254
```
255
 
256
If the address can not be determined or is unknown at this time (such as
257
after the socket has been closed), it MAY return a `NULL` value instead.
258
 
259
Otherwise, it will return the full address (URI) as a string value, such
260
as `tcp://127.0.0.1:8080`, `tcp://[::1]:80`, `tls://127.0.0.1:443`
261
`unix://example.sock` or `unix:///path/to/example.sock`.
262
Note that individual URI components are application specific and depend
263
on the underlying transport protocol.
264
 
265
If this is a TCP/IP based server and you only want the local port, you may
266
use something like this:
267
 
268
```php
269
$address = $server->getAddress();
270
$port = parse_url($address, PHP_URL_PORT);
271
echo 'Server listening on port ' . $port . PHP_EOL;
272
```
273
 
274
#### pause()
275
 
276
The `pause(): void` method can be used to
277
pause accepting new incoming connections.
278
 
279
Removes the socket resource from the EventLoop and thus stop accepting
280
new connections. Note that the listening socket stays active and is not
281
closed.
282
 
283
This means that new incoming connections will stay pending in the
284
operating system backlog until its configurable backlog is filled.
285
Once the backlog is filled, the operating system may reject further
286
incoming connections until the backlog is drained again by resuming
287
to accept new connections.
288
 
289
Once the server is paused, no futher `connection` events SHOULD
290
be emitted.
291
 
292
```php
293
$server->pause();
294
 
295
$server->on('connection', assertShouldNeverCalled());
296
```
297
 
298
This method is advisory-only, though generally not recommended, the
299
server MAY continue emitting `connection` events.
300
 
301
Unless otherwise noted, a successfully opened server SHOULD NOT start
302
in paused state.
303
 
304
You can continue processing events by calling `resume()` again.
305
 
306
Note that both methods can be called any number of times, in particular
307
calling `pause()` more than once SHOULD NOT have any effect.
308
Similarly, calling this after `close()` is a NO-OP.
309
 
310
#### resume()
311
 
312
The `resume(): void` method can be used to
313
resume accepting new incoming connections.
314
 
315
Re-attach the socket resource to the EventLoop after a previous `pause()`.
316
 
317
```php
318
$server->pause();
319
 
320
$loop->addTimer(1.0, function () use ($server) {
321
    $server->resume();
322
});
323
```
324
 
325
Note that both methods can be called any number of times, in particular
326
calling `resume()` without a prior `pause()` SHOULD NOT have any effect.
327
Similarly, calling this after `close()` is a NO-OP.
328
 
329
#### close()
330
 
331
The `close(): void` method can be used to
332
shut down this listening socket.
333
 
334
This will stop listening for new incoming connections on this socket.
335
 
336
```php
337
echo 'Shutting down server socket' . PHP_EOL;
338
$server->close();
339
```
340
 
341
Calling this method more than once on the same instance is a NO-OP.
342
 
343
### Server
344
 
345
The `Server` class is the main class in this package that implements the
346
[`ServerInterface`](#serverinterface) and allows you to accept incoming
347
streaming connections, such as plaintext TCP/IP or secure TLS connection streams.
348
Connections can also be accepted on Unix domain sockets.
349
 
350
```php
351
$server = new React\Socket\Server(8080, $loop);
352
```
353
 
354
As above, the `$uri` parameter can consist of only a port, in which case the
355
server will default to listening on the localhost address `127.0.0.1`,
356
which means it will not be reachable from outside of this system.
357
 
358
In order to use a random port assignment, you can use the port `0`:
359
 
360
```php
361
$server = new React\Socket\Server(0, $loop);
362
$address = $server->getAddress();
363
```
364
 
365
In order to change the host the socket is listening on, you can provide an IP
366
address through the first parameter provided to the constructor, optionally
367
preceded by the `tcp://` scheme:
368
 
369
```php
370
$server = new React\Socket\Server('192.168.0.1:8080', $loop);
371
```
372
 
373
If you want to listen on an IPv6 address, you MUST enclose the host in square
374
brackets:
375
 
376
```php
377
$server = new React\Socket\Server('[::1]:8080', $loop);
378
```
379
 
380
To listen on a Unix domain socket (UDS) path, you MUST prefix the URI with the
381
`unix://` scheme:
382
 
383
```php
384
$server = new React\Socket\Server('unix:///tmp/server.sock', $loop);
385
```
386
 
387
If the given URI is invalid, does not contain a port, any other scheme or if it
388
contains a hostname, it will throw an `InvalidArgumentException`:
389
 
390
```php
391
// throws InvalidArgumentException due to missing port
392
$server = new React\Socket\Server('127.0.0.1', $loop);
393
```
394
 
395
If the given URI appears to be valid, but listening on it fails (such as if port
396
is already in use or port below 1024 may require root access etc.), it will
397
throw a `RuntimeException`:
398
 
399
```php
400
$first = new React\Socket\Server(8080, $loop);
401
 
402
// throws RuntimeException because port is already in use
403
$second = new React\Socket\Server(8080, $loop);
404
```
405
 
406
> Note that these error conditions may vary depending on your system and/or
407
  configuration.
408
  See the exception message and code for more details about the actual error
409
  condition.
410
 
411
Optionally, you can specify [TCP socket context options](https://www.php.net/manual/en/context.socket.php)
412
for the underlying stream socket resource like this:
413
 
414
```php
415
$server = new React\Socket\Server('[::1]:8080', $loop, array(
416
    'tcp' => array(
417
        'backlog' => 200,
418
        'so_reuseport' => true,
419
        'ipv6_v6only' => true
420
    )
421
));
422
```
423
 
424
> Note that available [socket context options](https://www.php.net/manual/en/context.socket.php),
425
  their defaults and effects of changing these may vary depending on your system
426
  and/or PHP version.
427
  Passing unknown context options has no effect.
428
  The `backlog` context option defaults to `511` unless given explicitly.
429
  For BC reasons, you can also pass the TCP socket context options as a simple
430
  array without wrapping this in another array under the `tcp` key.
431
 
432
You can start a secure TLS (formerly known as SSL) server by simply prepending
433
the `tls://` URI scheme.
434
Internally, it will wait for plaintext TCP/IP connections and then performs a
435
TLS handshake for each connection.
436
It thus requires valid [TLS context options](https://www.php.net/manual/en/context.ssl.php),
437
which in its most basic form may look something like this if you're using a
438
PEM encoded certificate file:
439
 
440
```php
441
$server = new React\Socket\Server('tls://127.0.0.1:8080', $loop, array(
442
    'tls' => array(
443
        'local_cert' => 'server.pem'
444
    )
445
));
446
```
447
 
448
> Note that the certificate file will not be loaded on instantiation but when an
449
  incoming connection initializes its TLS context.
450
  This implies that any invalid certificate file paths or contents will only cause
451
  an `error` event at a later time.
452
 
453
If your private key is encrypted with a passphrase, you have to specify it
454
like this:
455
 
456
```php
457
$server = new React\Socket\Server('tls://127.0.0.1:8000', $loop, array(
458
    'tls' => array(
459
        'local_cert' => 'server.pem',
460
        'passphrase' => 'secret'
461
    )
462
));
463
```
464
 
465
By default, this server supports TLSv1.0+ and excludes support for legacy
466
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
467
want to negotiate with the remote side:
468
 
469
```php
470
$server = new React\Socket\Server('tls://127.0.0.1:8000', $loop, array(
471
    'tls' => array(
472
        'local_cert' => 'server.pem',
473
        'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
474
    )
475
));
476
```
477
 
478
> Note that available [TLS context options](https://www.php.net/manual/en/context.ssl.php),
479
  their defaults and effects of changing these may vary depending on your system
480
  and/or PHP version.
481
  The outer context array allows you to also use `tcp` (and possibly more)
482
  context options at the same time.
483
  Passing unknown context options has no effect.
484
  If you do not use the `tls://` scheme, then passing `tls` context options
485
  has no effect.
486
 
487
Whenever a client connects, it will emit a `connection` event with a connection
488
instance implementing [`ConnectionInterface`](#connectioninterface):
489
 
490
```php
491
$server->on('connection', function (React\Socket\ConnectionInterface $connection) {
492
    echo 'Plaintext connection from ' . $connection->getRemoteAddress() . PHP_EOL;
493
 
494
    $connection->write('hello there!' . PHP_EOL);
495
496
});
497
```
498
 
499
See also the [`ServerInterface`](#serverinterface) for more details.
500
 
501
> Note that the `Server` class is a concrete implementation for TCP/IP sockets.
502
  If you want to typehint in your higher-level protocol implementation, you SHOULD
503
  use the generic [`ServerInterface`](#serverinterface) instead.
504
 
505
### Advanced server usage
506
 
507
#### TcpServer
508
 
509
The `TcpServer` class implements the [`ServerInterface`](#serverinterface) and
510
is responsible for accepting plaintext TCP/IP connections.
511
 
512
```php
513
$server = new React\Socket\TcpServer(8080, $loop);
514
```
515
 
516
As above, the `$uri` parameter can consist of only a port, in which case the
517
server will default to listening on the localhost address `127.0.0.1`,
518
which means it will not be reachable from outside of this system.
519
 
520
In order to use a random port assignment, you can use the port `0`:
521
 
522
```php
523
$server = new React\Socket\TcpServer(0, $loop);
524
$address = $server->getAddress();
525
```
526
 
527
In order to change the host the socket is listening on, you can provide an IP
528
address through the first parameter provided to the constructor, optionally
529
preceded by the `tcp://` scheme:
530
 
531
```php
532
$server = new React\Socket\TcpServer('192.168.0.1:8080', $loop);
533
```
534
 
535
If you want to listen on an IPv6 address, you MUST enclose the host in square
536
brackets:
537
 
538
```php
539
$server = new React\Socket\TcpServer('[::1]:8080', $loop);
540
```
541
 
542
If the given URI is invalid, does not contain a port, any other scheme or if it
543
contains a hostname, it will throw an `InvalidArgumentException`:
544
 
545
```php
546
// throws InvalidArgumentException due to missing port
547
$server = new React\Socket\TcpServer('127.0.0.1', $loop);
548
```
549
 
550
If the given URI appears to be valid, but listening on it fails (such as if port
551
is already in use or port below 1024 may require root access etc.), it will
552
throw a `RuntimeException`:
553
 
554
```php
555
$first = new React\Socket\TcpServer(8080, $loop);
556
 
557
// throws RuntimeException because port is already in use
558
$second = new React\Socket\TcpServer(8080, $loop);
559
```
560
 
561
> Note that these error conditions may vary depending on your system and/or
562
configuration.
563
See the exception message and code for more details about the actual error
564
condition.
565
 
566
Optionally, you can specify [socket context options](https://www.php.net/manual/en/context.socket.php)
567
for the underlying stream socket resource like this:
568
 
569
```php
570
$server = new React\Socket\TcpServer('[::1]:8080', $loop, array(
571
    'backlog' => 200,
572
    'so_reuseport' => true,
573
    'ipv6_v6only' => true
574
));
575
```
576
 
577
> Note that available [socket context options](https://www.php.net/manual/en/context.socket.php),
578
their defaults and effects of changing these may vary depending on your system
579
and/or PHP version.
580
Passing unknown context options has no effect.
581
The `backlog` context option defaults to `511` unless given explicitly.
582
 
583
Whenever a client connects, it will emit a `connection` event with a connection
584
instance implementing [`ConnectionInterface`](#connectioninterface):
585
 
586
```php
587
$server->on('connection', function (React\Socket\ConnectionInterface $connection) {
588
    echo 'Plaintext connection from ' . $connection->getRemoteAddress() . PHP_EOL;
589
 
590
    $connection->write('hello there!' . PHP_EOL);
591
592
});
593
```
594
 
595
See also the [`ServerInterface`](#serverinterface) for more details.
596
 
597
#### SecureServer
598
 
599
The `SecureServer` class implements the [`ServerInterface`](#serverinterface)
600
and is responsible for providing a secure TLS (formerly known as SSL) server.
601
 
602
It does so by wrapping a [`TcpServer`](#tcpserver) instance which waits for plaintext
603
TCP/IP connections and then performs a TLS handshake for each connection.
604
It thus requires valid [TLS context options](https://www.php.net/manual/en/context.ssl.php),
605
which in its most basic form may look something like this if you're using a
606
PEM encoded certificate file:
607
 
608
```php
609
$server = new React\Socket\TcpServer(8000, $loop);
610
$server = new React\Socket\SecureServer($server, $loop, array(
611
    'local_cert' => 'server.pem'
612
));
613
```
614
 
615
> Note that the certificate file will not be loaded on instantiation but when an
616
incoming connection initializes its TLS context.
617
This implies that any invalid certificate file paths or contents will only cause
618
an `error` event at a later time.
619
 
620
If your private key is encrypted with a passphrase, you have to specify it
621
like this:
622
 
623
```php
624
$server = new React\Socket\TcpServer(8000, $loop);
625
$server = new React\Socket\SecureServer($server, $loop, array(
626
    'local_cert' => 'server.pem',
627
    'passphrase' => 'secret'
628
));
629
```
630
 
631
By default, this server supports TLSv1.0+ and excludes support for legacy
632
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
633
want to negotiate with the remote side:
634
 
635
```php
636
$server = new React\Socket\TcpServer(8000, $loop);
637
$server = new React\Socket\SecureServer($server, $loop, array(
638
    'local_cert' => 'server.pem',
639
    'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
640
));
641
```
642
 
643
> Note that available [TLS context options](https://www.php.net/manual/en/context.ssl.php),
644
their defaults and effects of changing these may vary depending on your system
645
and/or PHP version.
646
Passing unknown context options has no effect.
647
 
648
Whenever a client completes the TLS handshake, it will emit a `connection` event
649
with a connection instance implementing [`ConnectionInterface`](#connectioninterface):
650
 
651
```php
652
$server->on('connection', function (React\Socket\ConnectionInterface $connection) {
653
    echo 'Secure connection from' . $connection->getRemoteAddress() . PHP_EOL;
654
 
655
    $connection->write('hello there!' . PHP_EOL);
656
657
});
658
```
659
 
660
Whenever a client fails to perform a successful TLS handshake, it will emit an
661
`error` event and then close the underlying TCP/IP connection:
662
 
663
```php
664
$server->on('error', function (Exception $e) {
665
    echo 'Error' . $e->getMessage() . PHP_EOL;
666
});
667
```
668
 
669
See also the [`ServerInterface`](#serverinterface) for more details.
670
 
671
Note that the `SecureServer` class is a concrete implementation for TLS sockets.
672
If you want to typehint in your higher-level protocol implementation, you SHOULD
673
use the generic [`ServerInterface`](#serverinterface) instead.
674
 
675
> Advanced usage: Despite allowing any `ServerInterface` as first parameter,
676
you SHOULD pass a `TcpServer` instance as first parameter, unless you
677
know what you're doing.
678
Internally, the `SecureServer` has to set the required TLS context options on
679
the underlying stream resources.
680
These resources are not exposed through any of the interfaces defined in this
681
package, but only through the internal `Connection` class.
682
The `TcpServer` class is guaranteed to emit connections that implement
683
the `ConnectionInterface` and uses the internal `Connection` class in order to
684
expose these underlying resources.
685
If you use a custom `ServerInterface` and its `connection` event does not
686
meet this requirement, the `SecureServer` will emit an `error` event and
687
then close the underlying connection.
688
 
689
#### UnixServer
690
 
691
The `UnixServer` class implements the [`ServerInterface`](#serverinterface) and
692
is responsible for accepting connections on Unix domain sockets (UDS).
693
 
694
```php
695
$server = new React\Socket\UnixServer('/tmp/server.sock', $loop);
696
```
697
 
698
As above, the `$uri` parameter can consist of only a socket path or socket path
699
prefixed by the `unix://` scheme.
700
 
701
If the given URI appears to be valid, but listening on it fails (such as if the
702
socket is already in use or the file not accessible etc.), it will throw a
703
`RuntimeException`:
704
 
705
```php
706
$first = new React\Socket\UnixServer('/tmp/same.sock', $loop);
707
 
708
// throws RuntimeException because socket is already in use
709
$second = new React\Socket\UnixServer('/tmp/same.sock', $loop);
710
```
711
 
712
> Note that these error conditions may vary depending on your system and/or
713
  configuration.
714
  In particular, Zend PHP does only report "Unknown error" when the UDS path
715
  already exists and can not be bound. You may want to check `is_file()` on the
716
  given UDS path to report a more user-friendly error message in this case.
717
  See the exception message and code for more details about the actual error
718
  condition.
719
 
720
Whenever a client connects, it will emit a `connection` event with a connection
721
instance implementing [`ConnectionInterface`](#connectioninterface):
722
 
723
```php
724
$server->on('connection', function (React\Socket\ConnectionInterface $connection) {
725
    echo 'New connection' . PHP_EOL;
726
 
727
    $connection->write('hello there!' . PHP_EOL);
728
729
});
730
```
731
 
732
See also the [`ServerInterface`](#serverinterface) for more details.
733
 
734
#### LimitingServer
735
 
736
The `LimitingServer` decorator wraps a given `ServerInterface` and is responsible
737
for limiting and keeping track of open connections to this server instance.
738
 
739
Whenever the underlying server emits a `connection` event, it will check its
740
limits and then either
741
 - keep track of this connection by adding it to the list of
742
   open connections and then forward the `connection` event
743
 - or reject (close) the connection when its limits are exceeded and will
744
   forward an `error` event instead.
745
 
746
Whenever a connection closes, it will remove this connection from the list of
747
open connections.
748
 
749
```php
750
$server = new React\Socket\LimitingServer($server, 100);
751
$server->on('connection', function (React\Socket\ConnectionInterface $connection) {
752
    $connection->write('hello there!' . PHP_EOL);
753
754
});
755
```
756
 
757
See also the [second example](examples) for more details.
758
 
759
You have to pass a maximum number of open connections to ensure
760
the server will automatically reject (close) connections once this limit
761
is exceeded. In this case, it will emit an `error` event to inform about
762
this and no `connection` event will be emitted.
763
 
764
```php
765
$server = new React\Socket\LimitingServer($server, 100);
766
$server->on('connection', function (React\Socket\ConnectionInterface $connection) {
767
    $connection->write('hello there!' . PHP_EOL);
768
769
});
770
```
771
 
772
You MAY pass a `null` limit in order to put no limit on the number of
773
open connections and keep accepting new connection until you run out of
774
operating system resources (such as open file handles). This may be
775
useful if you do not want to take care of applying a limit but still want
776
to use the `getConnections()` method.
777
 
778
You can optionally configure the server to pause accepting new
779
connections once the connection limit is reached. In this case, it will
780
pause the underlying server and no longer process any new connections at
781
all, thus also no longer closing any excessive connections.
782
The underlying operating system is responsible for keeping a backlog of
783
pending connections until its limit is reached, at which point it will
784
start rejecting further connections.
785
Once the server is below the connection limit, it will continue consuming
786
connections from the backlog and will process any outstanding data on
787
each connection.
788
This mode may be useful for some protocols that are designed to wait for
789
a response message (such as HTTP), but may be less useful for other
790
protocols that demand immediate responses (such as a "welcome" message in
791
an interactive chat).
792
 
793
```php
794
$server = new React\Socket\LimitingServer($server, 100, true);
795
$server->on('connection', function (React\Socket\ConnectionInterface $connection) {
796
    $connection->write('hello there!' . PHP_EOL);
797
798
});
799
```
800
 
801
##### getConnections()
802
 
803
The `getConnections(): ConnectionInterface[]` method can be used to
804
return an array with all currently active connections.
805
 
806
```php
807
foreach ($server->getConnection() as $connection) {
808
    $connection->write('Hi!');
809
}
810
```
811
 
812
## Client usage
813
 
814
### ConnectorInterface
815
 
816
The `ConnectorInterface` is responsible for providing an interface for
817
establishing streaming connections, such as a normal TCP/IP connection.
818
 
819
This is the main interface defined in this package and it is used throughout
820
React's vast ecosystem.
821
 
822
Most higher-level components (such as HTTP, database or other networking
823
service clients) accept an instance implementing this interface to create their
824
TCP/IP connection to the underlying networking service.
825
This is usually done via dependency injection, so it's fairly simple to actually
826
swap this implementation against any other implementation of this interface.
827
 
828
The interface only offers a single method:
829
 
830
#### connect()
831
 
832
The `connect(string $uri): PromiseInterface<ConnectionInterface,Exception>` method
833
can be used to create a streaming connection to the given remote address.
834
 
835
It returns a [Promise](https://github.com/reactphp/promise) which either
836
fulfills with a stream implementing [`ConnectionInterface`](#connectioninterface)
837
on success or rejects with an `Exception` if the connection is not successful:
838
 
839
```php
840
$connector->connect('google.com:443')->then(
841
    function (React\Socket\ConnectionInterface $connection) {
842
        // connection successfully established
843
    },
844
    function (Exception $error) {
845
        // failed to connect due to $error
846
    }
847
);
848
```
849
 
850
See also [`ConnectionInterface`](#connectioninterface) for more details.
851
 
852
The returned Promise MUST be implemented in such a way that it can be
853
cancelled when it is still pending. Cancelling a pending promise MUST
854
reject its value with an `Exception`. It SHOULD clean up any underlying
855
resources and references as applicable:
856
 
857
```php
858
$promise = $connector->connect($uri);
859
 
860
$promise->cancel();
861
```
862
 
863
### Connector
864
 
865
The `Connector` class is the main class in this package that implements the
866
[`ConnectorInterface`](#connectorinterface) and allows you to create streaming connections.
867
 
868
You can use this connector to create any kind of streaming connections, such
869
as plaintext TCP/IP, secure TLS or local Unix connection streams.
870
 
871
It binds to the main event loop and can be used like this:
872
 
873
```php
874
$loop = React\EventLoop\Factory::create();
875
$connector = new React\Socket\Connector($loop);
876
 
877
$connector->connect($uri)->then(function (React\Socket\ConnectionInterface $connection) {
878
    $connection->write('...');
879
    $connection->end();
880
});
881
 
882
$loop->run();
883
```
884
 
885
In order to create a plaintext TCP/IP connection, you can simply pass a host
886
and port combination like this:
887
 
888
```php
889
$connector->connect('www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
890
    $connection->write('...');
891
    $connection->end();
892
});
893
```
894
 
895
> If you do no specify a URI scheme in the destination URI, it will assume
896
  `tcp://` as a default and establish a plaintext TCP/IP connection.
897
  Note that TCP/IP connections require a host and port part in the destination
898
  URI like above, all other URI components are optional.
899
 
900
In order to create a secure TLS connection, you can use the `tls://` URI scheme
901
like this:
902
 
903
```php
904
$connector->connect('tls://www.google.com:443')->then(function (React\Socket\ConnectionInterface $connection) {
905
    $connection->write('...');
906
    $connection->end();
907
});
908
```
909
 
910
In order to create a local Unix domain socket connection, you can use the
911
`unix://` URI scheme like this:
912
 
913
```php
914
$connector->connect('unix:///tmp/demo.sock')->then(function (React\Socket\ConnectionInterface $connection) {
915
    $connection->write('...');
916
    $connection->end();
917
});
918
```
919
 
920
> The [`getRemoteAddress()`](#getremoteaddress) method will return the target
921
  Unix domain socket (UDS) path as given to the `connect()` method, including
922
  the `unix://` scheme, for example `unix:///tmp/demo.sock`.
923
  The [`getLocalAddress()`](#getlocaladdress) method will most likely return a
924
  `null` value as this value is not applicable to UDS connections here.
925
 
926
Under the hood, the `Connector` is implemented as a *higher-level facade*
927
for the lower-level connectors implemented in this package. This means it
928
also shares all of their features and implementation details.
929
If you want to typehint in your higher-level protocol implementation, you SHOULD
930
use the generic [`ConnectorInterface`](#connectorinterface) instead.
931
 
932
As of `v1.4.0`, the `Connector` class defaults to using the
933
[happy eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to
934
automatically connect over IPv4 or IPv6 when a hostname is given.
935
This automatically attempts to connect using both IPv4 and IPv6 at the same time
936
(preferring IPv6), thus avoiding the usual problems faced by users with imperfect
937
IPv6 connections or setups.
938
If you want to revert to the old behavior of only doing an IPv4 lookup and
939
only attempt a single IPv4 connection, you can set up the `Connector` like this:
940
 
941
```php
942
$connector = new React\Socket\Connector($loop, array(
943
    'happy_eyeballs' => false
944
));
945
```
946
 
947
Similarly, you can also affect the default DNS behavior as follows.
948
The `Connector` class will try to detect your system DNS settings (and uses
949
Google's public DNS server `8.8.8.8` as a fallback if unable to determine your
950
system settings) to resolve all public hostnames into underlying IP addresses by
951
default.
952
If you explicitly want to use a custom DNS server (such as a local DNS relay or
953
a company wide DNS server), you can set up the `Connector` like this:
954
 
955
```php
956
$connector = new React\Socket\Connector($loop, array(
957
    'dns' => '127.0.1.1'
958
));
959
 
960
$connector->connect('localhost:80')->then(function (React\Socket\ConnectionInterface $connection) {
961
    $connection->write('...');
962
    $connection->end();
963
});
964
```
965
 
966
If you do not want to use a DNS resolver at all and want to connect to IP
967
addresses only, you can also set up your `Connector` like this:
968
 
969
```php
970
$connector = new React\Socket\Connector($loop, array(
971
    'dns' => false
972
));
973
 
974
$connector->connect('127.0.0.1:80')->then(function (React\Socket\ConnectionInterface $connection) {
975
    $connection->write('...');
976
    $connection->end();
977
});
978
```
979
 
980
Advanced: If you need a custom DNS `React\Dns\Resolver\ResolverInterface` instance, you
981
can also set up your `Connector` like this:
982
 
983
```php
984
$dnsResolverFactory = new React\Dns\Resolver\Factory();
985
$resolver = $dnsResolverFactory->createCached('127.0.1.1', $loop);
986
 
987
$connector = new React\Socket\Connector($loop, array(
988
    'dns' => $resolver
989
));
990
 
991
$connector->connect('localhost:80')->then(function (React\Socket\ConnectionInterface $connection) {
992
    $connection->write('...');
993
    $connection->end();
994
});
995
```
996
 
997
By default, the `tcp://` and `tls://` URI schemes will use timeout value that
998
respects your `default_socket_timeout` ini setting (which defaults to 60s).
999
If you want a custom timeout value, you can simply pass this like this:
1000
 
1001
```php
1002
$connector = new React\Socket\Connector($loop, array(
1003
    'timeout' => 10.0
1004
));
1005
```
1006
 
1007
Similarly, if you do not want to apply a timeout at all and let the operating
1008
system handle this, you can pass a boolean flag like this:
1009
 
1010
```php
1011
$connector = new React\Socket\Connector($loop, array(
1012
    'timeout' => false
1013
));
1014
```
1015
 
1016
By default, the `Connector` supports the `tcp://`, `tls://` and `unix://`
1017
URI schemes. If you want to explicitly prohibit any of these, you can simply
1018
pass boolean flags like this:
1019
 
1020
```php
1021
// only allow secure TLS connections
1022
$connector = new React\Socket\Connector($loop, array(
1023
    'tcp' => false,
1024
    'tls' => true,
1025
    'unix' => false,
1026
));
1027
 
1028
$connector->connect('tls://google.com:443')->then(function (React\Socket\ConnectionInterface $connection) {
1029
    $connection->write('...');
1030
    $connection->end();
1031
});
1032
```
1033
 
1034
The `tcp://` and `tls://` also accept additional context options passed to
1035
the underlying connectors.
1036
If you want to explicitly pass additional context options, you can simply
1037
pass arrays of context options like this:
1038
 
1039
```php
1040
// allow insecure TLS connections
1041
$connector = new React\Socket\Connector($loop, array(
1042
    'tcp' => array(
1043
        'bindto' => '192.168.0.1:0'
1044
    ),
1045
    'tls' => array(
1046
        'verify_peer' => false,
1047
        'verify_peer_name' => false
1048
    ),
1049
));
1050
 
1051
$connector->connect('tls://localhost:443')->then(function (React\Socket\ConnectionInterface $connection) {
1052
    $connection->write('...');
1053
    $connection->end();
1054
});
1055
```
1056
 
1057
By default, this connector supports TLSv1.0+ and excludes support for legacy
1058
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
1059
want to negotiate with the remote side:
1060
 
1061
```php
1062
$connector = new React\Socket\Connector($loop, array(
1063
    'tls' => array(
1064
        'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
1065
    )
1066
));
1067
```
1068
 
1069
> For more details about context options, please refer to the PHP documentation
1070
  about [socket context options](https://www.php.net/manual/en/context.socket.php)
1071
  and [SSL context options](https://www.php.net/manual/en/context.ssl.php).
1072
 
1073
Advanced: By default, the `Connector` supports the `tcp://`, `tls://` and
1074
`unix://` URI schemes.
1075
For this, it sets up the required connector classes automatically.
1076
If you want to explicitly pass custom connectors for any of these, you can simply
1077
pass an instance implementing the `ConnectorInterface` like this:
1078
 
1079
```php
1080
$dnsResolverFactory = new React\Dns\Resolver\Factory();
1081
$resolver = $dnsResolverFactory->createCached('127.0.1.1', $loop);
1082
$tcp = new React\Socket\HappyEyeBallsConnector($loop, new React\Socket\TcpConnector($loop), $resolver);
1083
 
1084
$tls = new React\Socket\SecureConnector($tcp, $loop);
1085
 
1086
$unix = new React\Socket\UnixConnector($loop);
1087
 
1088
$connector = new React\Socket\Connector($loop, array(
1089
    'tcp' => $tcp,
1090
    'tls' => $tls,
1091
    'unix' => $unix,
1092
 
1093
    'dns' => false,
1094
    'timeout' => false,
1095
));
1096
 
1097
$connector->connect('google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
1098
    $connection->write('...');
1099
    $connection->end();
1100
});
1101
```
1102
 
1103
> Internally, the `tcp://` connector will always be wrapped by the DNS resolver,
1104
  unless you disable DNS like in the above example. In this case, the `tcp://`
1105
  connector receives the actual hostname instead of only the resolved IP address
1106
  and is thus responsible for performing the lookup.
1107
  Internally, the automatically created `tls://` connector will always wrap the
1108
  underlying `tcp://` connector for establishing the underlying plaintext
1109
  TCP/IP connection before enabling secure TLS mode. If you want to use a custom
1110
  underlying `tcp://` connector for secure TLS connections only, you may
1111
  explicitly pass a `tls://` connector like above instead.
1112
  Internally, the `tcp://` and `tls://` connectors will always be wrapped by
1113
  `TimeoutConnector`, unless you disable timeouts like in the above example.
1114
 
1115
### Advanced client usage
1116
 
1117
#### TcpConnector
1118
 
1119
The `TcpConnector` class implements the
1120
[`ConnectorInterface`](#connectorinterface) and allows you to create plaintext
1121
TCP/IP connections to any IP-port-combination:
1122
 
1123
```php
1124
$tcpConnector = new React\Socket\TcpConnector($loop);
1125
 
1126
$tcpConnector->connect('127.0.0.1:80')->then(function (React\Socket\ConnectionInterface $connection) {
1127
    $connection->write('...');
1128
    $connection->end();
1129
});
1130
 
1131
$loop->run();
1132
```
1133
 
1134
See also the [examples](examples).
1135
 
1136
Pending connection attempts can be cancelled by cancelling its pending promise like so:
1137
 
1138
```php
1139
$promise = $tcpConnector->connect('127.0.0.1:80');
1140
 
1141
$promise->cancel();
1142
```
1143
 
1144
Calling `cancel()` on a pending promise will close the underlying socket
1145
resource, thus cancelling the pending TCP/IP connection, and reject the
1146
resulting promise.
1147
 
1148
You can optionally pass additional
1149
[socket context options](https://www.php.net/manual/en/context.socket.php)
1150
to the constructor like this:
1151
 
1152
```php
1153
$tcpConnector = new React\Socket\TcpConnector($loop, array(
1154
    'bindto' => '192.168.0.1:0'
1155
));
1156
```
1157
 
1158
Note that this class only allows you to connect to IP-port-combinations.
1159
If the given URI is invalid, does not contain a valid IP address and port
1160
or contains any other scheme, it will reject with an
1161
`InvalidArgumentException`:
1162
 
1163
If the given URI appears to be valid, but connecting to it fails (such as if
1164
the remote host rejects the connection etc.), it will reject with a
1165
`RuntimeException`.
1166
 
1167
If you want to connect to hostname-port-combinations, see also the following chapter.
1168
 
1169
> Advanced usage: Internally, the `TcpConnector` allocates an empty *context*
1170
resource for each stream resource.
1171
If the destination URI contains a `hostname` query parameter, its value will
1172
be used to set up the TLS peer name.
1173
This is used by the `SecureConnector` and `DnsConnector` to verify the peer
1174
name and can also be used if you want a custom TLS peer name.
1175
 
1176
#### HappyEyeBallsConnector
1177
 
1178
The `HappyEyeBallsConnector` class implements the
1179
[`ConnectorInterface`](#connectorinterface) and allows you to create plaintext
1180
TCP/IP connections to any hostname-port-combination. Internally it implements the 
1181
happy eyeballs algorithm from [`RFC6555`](https://tools.ietf.org/html/rfc6555) and 
1182
[`RFC8305`](https://tools.ietf.org/html/rfc8305) to support IPv6 and IPv4 hostnames.
1183
 
1184
It does so by decorating a given `TcpConnector` instance so that it first
1185
looks up the given domain name via DNS (if applicable) and then establishes the
1186
underlying TCP/IP connection to the resolved target IP address.
1187
 
1188
Make sure to set up your DNS resolver and underlying TCP connector like this:
1189
 
1190
```php
1191
$dnsResolverFactory = new React\Dns\Resolver\Factory();
1192
$dns = $dnsResolverFactory->createCached('8.8.8.8', $loop);
1193
 
1194
$dnsConnector = new React\Socket\HappyEyeBallsConnector($loop, $tcpConnector, $dns);
1195
 
1196
$dnsConnector->connect('www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
1197
    $connection->write('...');
1198
    $connection->end();
1199
});
1200
 
1201
$loop->run();
1202
```
1203
 
1204
See also the [examples](examples).
1205
 
1206
Pending connection attempts can be cancelled by cancelling its pending promise like so:
1207
 
1208
```php
1209
$promise = $dnsConnector->connect('www.google.com:80');
1210
 
1211
$promise->cancel();
1212
```
1213
 
1214
Calling `cancel()` on a pending promise will cancel the underlying DNS lookups
1215
and/or the underlying TCP/IP connection(s) and reject the resulting promise.
1216
 
1217
 
1218
> Advanced usage: Internally, the `HappyEyeBallsConnector` relies on a `Resolver` to
1219
look up the IP addresses for the given hostname.
1220
It will then replace the hostname in the destination URI with this IP's and
1221
append a `hostname` query parameter and pass this updated URI to the underlying
1222
connector. 
1223
The Happy Eye Balls algorithm describes looking the IPv6 and IPv4 address for 
1224
the given hostname so this connector sends out two DNS lookups for the A and 
1225
AAAA records. It then uses all IP addresses (both v6 and v4) and tries to 
1226
connect to all of them with a 50ms interval in between. Alterating between IPv6 
1227
and IPv4 addresses. When a connection is established all the other DNS lookups 
1228
and connection attempts are cancelled.
1229
 
1230
#### DnsConnector
1231
 
1232
The `DnsConnector` class implements the
1233
[`ConnectorInterface`](#connectorinterface) and allows you to create plaintext
1234
TCP/IP connections to any hostname-port-combination.
1235
 
1236
It does so by decorating a given `TcpConnector` instance so that it first
1237
looks up the given domain name via DNS (if applicable) and then establishes the
1238
underlying TCP/IP connection to the resolved target IP address.
1239
 
1240
Make sure to set up your DNS resolver and underlying TCP connector like this:
1241
 
1242
```php
1243
$dnsResolverFactory = new React\Dns\Resolver\Factory();
1244
$dns = $dnsResolverFactory->createCached('8.8.8.8', $loop);
1245
 
1246
$dnsConnector = new React\Socket\DnsConnector($tcpConnector, $dns);
1247
 
1248
$dnsConnector->connect('www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
1249
    $connection->write('...');
1250
    $connection->end();
1251
});
1252
 
1253
$loop->run();
1254
```
1255
 
1256
See also the [examples](examples).
1257
 
1258
Pending connection attempts can be cancelled by cancelling its pending promise like so:
1259
 
1260
```php
1261
$promise = $dnsConnector->connect('www.google.com:80');
1262
 
1263
$promise->cancel();
1264
```
1265
 
1266
Calling `cancel()` on a pending promise will cancel the underlying DNS lookup
1267
and/or the underlying TCP/IP connection and reject the resulting promise.
1268
 
1269
> Advanced usage: Internally, the `DnsConnector` relies on a `React\Dns\Resolver\ResolverInterface`
1270
to look up the IP address for the given hostname.
1271
It will then replace the hostname in the destination URI with this IP and
1272
append a `hostname` query parameter and pass this updated URI to the underlying
1273
connector.
1274
The underlying connector is thus responsible for creating a connection to the
1275
target IP address, while this query parameter can be used to check the original
1276
hostname and is used by the `TcpConnector` to set up the TLS peer name.
1277
If a `hostname` is given explicitly, this query parameter will not be modified,
1278
which can be useful if you want a custom TLS peer name.
1279
 
1280
#### SecureConnector
1281
 
1282
The `SecureConnector` class implements the
1283
[`ConnectorInterface`](#connectorinterface) and allows you to create secure
1284
TLS (formerly known as SSL) connections to any hostname-port-combination.
1285
 
1286
It does so by decorating a given `DnsConnector` instance so that it first
1287
creates a plaintext TCP/IP connection and then enables TLS encryption on this
1288
stream.
1289
 
1290
```php
1291
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop);
1292
 
1293
$secureConnector->connect('www.google.com:443')->then(function (React\Socket\ConnectionInterface $connection) {
1294
    $connection->write("GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n");
1295
    ...
1296
});
1297
 
1298
$loop->run();
1299
```
1300
 
1301
See also the [examples](examples).
1302
 
1303
Pending connection attempts can be cancelled by cancelling its pending promise like so:
1304
 
1305
```php
1306
$promise = $secureConnector->connect('www.google.com:443');
1307
 
1308
$promise->cancel();
1309
```
1310
 
1311
Calling `cancel()` on a pending promise will cancel the underlying TCP/IP
1312
connection and/or the SSL/TLS negotiation and reject the resulting promise.
1313
 
1314
You can optionally pass additional
1315
[SSL context options](https://www.php.net/manual/en/context.ssl.php)
1316
to the constructor like this:
1317
 
1318
```php
1319
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
1320
    'verify_peer' => false,
1321
    'verify_peer_name' => false
1322
));
1323
```
1324
 
1325
By default, this connector supports TLSv1.0+ and excludes support for legacy
1326
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
1327
want to negotiate with the remote side:
1328
 
1329
```php
1330
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
1331
    'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
1332
));
1333
```
1334
 
1335
> Advanced usage: Internally, the `SecureConnector` relies on setting up the
1336
required *context options* on the underlying stream resource.
1337
It should therefor be used with a `TcpConnector` somewhere in the connector
1338
stack so that it can allocate an empty *context* resource for each stream
1339
resource and verify the peer name.
1340
Failing to do so may result in a TLS peer name mismatch error or some hard to
1341
trace race conditions, because all stream resources will use a single, shared
1342
*default context* resource otherwise.
1343
 
1344
#### TimeoutConnector
1345
 
1346
The `TimeoutConnector` class implements the
1347
[`ConnectorInterface`](#connectorinterface) and allows you to add timeout
1348
handling to any existing connector instance.
1349
 
1350
It does so by decorating any given [`ConnectorInterface`](#connectorinterface)
1351
instance and starting a timer that will automatically reject and abort any
1352
underlying connection attempt if it takes too long.
1353
 
1354
```php
1355
$timeoutConnector = new React\Socket\TimeoutConnector($connector, 3.0, $loop);
1356
 
1357
$timeoutConnector->connect('google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
1358
    // connection succeeded within 3.0 seconds
1359
});
1360
```
1361
 
1362
See also any of the [examples](examples).
1363
 
1364
Pending connection attempts can be cancelled by cancelling its pending promise like so:
1365
 
1366
```php
1367
$promise = $timeoutConnector->connect('google.com:80');
1368
 
1369
$promise->cancel();
1370
```
1371
 
1372
Calling `cancel()` on a pending promise will cancel the underlying connection
1373
attempt, abort the timer and reject the resulting promise.
1374
 
1375
#### UnixConnector
1376
 
1377
The `UnixConnector` class implements the
1378
[`ConnectorInterface`](#connectorinterface) and allows you to connect to
1379
Unix domain socket (UDS) paths like this:
1380
 
1381
```php
1382
$connector = new React\Socket\UnixConnector($loop);
1383
 
1384
$connector->connect('/tmp/demo.sock')->then(function (React\Socket\ConnectionInterface $connection) {
1385
    $connection->write("HELLO\n");
1386
});
1387
 
1388
$loop->run();
1389
```
1390
 
1391
Connecting to Unix domain sockets is an atomic operation, i.e. its promise will
1392
settle (either resolve or reject) immediately.
1393
As such, calling `cancel()` on the resulting promise has no effect.
1394
 
1395
> The [`getRemoteAddress()`](#getremoteaddress) method will return the target
1396
  Unix domain socket (UDS) path as given to the `connect()` method, prepended
1397
  with the `unix://` scheme, for example `unix:///tmp/demo.sock`.
1398
  The [`getLocalAddress()`](#getlocaladdress) method will most likely return a
1399
  `null` value as this value is not applicable to UDS connections here.
1400
 
1401
#### FixedUriConnector
1402
 
1403
The `FixedUriConnector` class implements the
1404
[`ConnectorInterface`](#connectorinterface) and decorates an existing Connector
1405
to always use a fixed, preconfigured URI.
1406
 
1407
This can be useful for consumers that do not support certain URIs, such as
1408
when you want to explicitly connect to a Unix domain socket (UDS) path
1409
instead of connecting to a default address assumed by an higher-level API:
1410
 
1411
```php
1412
$connector = new React\Socket\FixedUriConnector(
1413
    'unix:///var/run/docker.sock',
1414
    new React\Socket\UnixConnector($loop)
1415
);
1416
 
1417
// destination will be ignored, actually connects to Unix domain socket
1418
$promise = $connector->connect('localhost:80');
1419
```
1420
 
1421
## Install
1422
 
1423
The recommended way to install this library is [through Composer](https://getcomposer.org).
1424
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
1425
 
1426
This project follows [SemVer](https://semver.org/).
1427
This will install the latest supported version:
1428
 
1429
```bash
1430
$ composer require react/socket:^1.6
1431
```
1432
 
1433
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
1434
 
1435
This project aims to run on any platform and thus does not require any PHP
1436
extensions and supports running on legacy PHP 5.3 through current PHP 7+ and HHVM.
1437
It's *highly recommended to use PHP 7+* for this project, partly due to its vast
1438
performance improvements and partly because legacy PHP versions require several
1439
workarounds as described below.
1440
 
1441
Secure TLS connections received some major upgrades starting with PHP 5.6, with
1442
the defaults now being more secure, while older versions required explicit
1443
context options.
1444
This library does not take responsibility over these context options, so it's
1445
up to consumers of this library to take care of setting appropriate context
1446
options as described above.
1447
 
1448
PHP < 7.3.3 (and PHP < 7.2.15) suffers from a bug where feof() might
1449
block with 100% CPU usage on fragmented TLS records.
1450
We try to work around this by always consuming the complete receive
1451
buffer at once to avoid stale data in TLS buffers. This is known to
1452
work around high CPU usage for well-behaving peers, but this may
1453
cause very large data chunks for high throughput scenarios. The buggy
1454
behavior can still be triggered due to network I/O buffers or
1455
malicious peers on affected versions, upgrading is highly recommended.
1456
 
1457
PHP < 7.1.4 (and PHP < 7.0.18) suffers from a bug when writing big
1458
chunks of data over TLS streams at once.
1459
We try to work around this by limiting the write chunk size to 8192
1460
bytes for older PHP versions only.
1461
This is only a work-around and has a noticable performance penalty on
1462
affected versions.
1463
 
1464
This project also supports running on HHVM.
1465
Note that really old HHVM < 3.8 does not support secure TLS connections, as it
1466
lacks the required `stream_socket_enable_crypto()` function.
1467
As such, trying to create a secure TLS connections on affected versions will
1468
return a rejected promise instead.
1469
This issue is also covered by our test suite, which will skip related tests
1470
on affected versions.
1471
 
1472
## Tests
1473
 
1474
To run the test suite, you first need to clone this repo and then install all
1475
dependencies [through Composer](https://getcomposer.org):
1476
 
1477
```bash
1478
$ composer install
1479
```
1480
 
1481
To run the test suite, go to the project root and run:
1482
 
1483
```bash
1484
$ php vendor/bin/phpunit
1485
```
1486
 
1487
The test suite also contains a number of functional integration tests that rely
1488
on a stable internet connection.
1489
If you do not want to run these, they can simply be skipped like this:
1490
 
1491
```bash
1492
$ php vendor/bin/phpunit --exclude-group internet
1493
```
1494
 
1495
## License
1496
 
1497
MIT, see [LICENSE file](LICENSE).