diff --git a/README.md b/README.md index f8e7ae2b..9fb2ec5d 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ handle multiple concurrent connections without blocking. * [pause()](#pause) * [resume()](#resume) * [close()](#close) - * [Server](#server) + * [SocketServer](#socketserver) * [Advanced server usage](#advanced-server-usage) * [TcpServer](#tcpserver) * [SecureServer](#secureserver) @@ -58,7 +58,7 @@ handle multiple concurrent connections without blocking. Here is a server that closes the connection if you send it anything: ```php -$socket = new React\Socket\Server('127.0.0.1:8080'); +$socket = new React\Socket\SocketServer('127.0.0.1:8080'); $socket->on('connection', function (React\Socket\ConnectionInterface $connection) { $connection->write("Hello " . $connection->getRemoteAddress() . "!\n"); @@ -214,7 +214,7 @@ The `connection` event will be emitted whenever a new connection has been established, i.e. a new client connects to this server socket: ```php -$server->on('connection', function (React\Socket\ConnectionInterface $connection) { +$socket->on('connection', function (React\Socket\ConnectionInterface $connection) { echo 'new connection' . PHP_EOL; }); ``` @@ -228,7 +228,7 @@ The `error` event will be emitted whenever there's an error accepting a new connection from a client. ```php -$server->on('error', function (Exception $e) { +$socket->on('error', function (Exception $e) { echo 'error: ' . $e->getMessage() . PHP_EOL; }); ``` @@ -243,7 +243,7 @@ The `getAddress(): ?string` method can be used to return the full address (URI) this server is currently listening on. ```php -$address = $server->getAddress(); +$address = $socket->getAddress(); echo 'Server listening on ' . $address . PHP_EOL; ``` @@ -260,7 +260,7 @@ If this is a TCP/IP based server and you only want the local port, you may use something like this: ```php -$address = $server->getAddress(); +$address = $socket->getAddress(); $port = parse_url($address, PHP_URL_PORT); echo 'Server listening on port ' . $port . PHP_EOL; ``` @@ -284,9 +284,9 @@ Once the server is paused, no futher `connection` events SHOULD be emitted. ```php -$server->pause(); +$socket->pause(); -$server->on('connection', assertShouldNeverCalled()); +$socket->on('connection', assertShouldNeverCalled()); ``` This method is advisory-only, though generally not recommended, the @@ -309,10 +309,10 @@ resume accepting new incoming connections. Re-attach the socket resource to the EventLoop after a previous `pause()`. ```php -$server->pause(); +$socket->pause(); -Loop::addTimer(1.0, function () use ($server) { - $server->resume(); +Loop::addTimer(1.0, function () use ($socket) { + $socket->resume(); }); ``` @@ -329,53 +329,55 @@ This will stop listening for new incoming connections on this socket. ```php echo 'Shutting down server socket' . PHP_EOL; -$server->close(); +$socket->close(); ``` Calling this method more than once on the same instance is a NO-OP. -### Server +### SocketServer -The `Server` class is the main class in this package that implements the + + +The `SocketServer` class is the main class in this package that implements the [`ServerInterface`](#serverinterface) and allows you to accept incoming streaming connections, such as plaintext TCP/IP or secure TLS connection streams. -Connections can also be accepted on Unix domain sockets. -```php -$server = new React\Socket\Server(8080); -``` - -As above, the `$uri` parameter can consist of only a port, in which case the -server will default to listening on the localhost address `127.0.0.1`, -which means it will not be reachable from outside of this system. - -In order to use a random port assignment, you can use the port `0`: +In order to accept plaintext TCP/IP connections, you can simply pass a host +and port combination like this: ```php -$server = new React\Socket\Server(0); -$address = $server->getAddress(); +$socket = new React\Socket\SocketServer('127.0.0.1:8080'); ``` +Listening on the localhost address `127.0.0.1` means it will not be reachable from +outside of this system. In order to change the host the socket is listening on, you can provide an IP -address through the first parameter provided to the constructor, optionally -preceded by the `tcp://` scheme: +address of an interface or use the special `0.0.0.0` address to listen on all +interfaces: ```php -$server = new React\Socket\Server('192.168.0.1:8080'); +$socket = new React\Socket\SocketServer('0.0.0.0:8080'); ``` If you want to listen on an IPv6 address, you MUST enclose the host in square brackets: ```php -$server = new React\Socket\Server('[::1]:8080'); +$socket = new React\Socket\SocketServer('[::1]:8080'); +``` + +In order to use a random port assignment, you can use the port `0`: + +```php +$socket = new React\Socket\SocketServer('127.0.0.1:0'); +$address = $socket->getAddress(); ``` To listen on a Unix domain socket (UDS) path, you MUST prefix the URI with the `unix://` scheme: ```php -$server = new React\Socket\Server('unix:///tmp/server.sock'); +$socket = new React\Socket\SocketServer('unix:///tmp/server.sock'); ``` If the given URI is invalid, does not contain a port, any other scheme or if it @@ -383,7 +385,7 @@ contains a hostname, it will throw an `InvalidArgumentException`: ```php // throws InvalidArgumentException due to missing port -$server = new React\Socket\Server('127.0.0.1'); +$socket = new React\Socket\SocketServer('127.0.0.1'); ``` If the given URI appears to be valid, but listening on it fails (such as if port @@ -391,10 +393,10 @@ is already in use or port below 1024 may require root access etc.), it will throw a `RuntimeException`: ```php -$first = new React\Socket\Server(8080); +$first = new React\Socket\SocketServer('127.0.0.1:8080'); // throws RuntimeException because port is already in use -$second = new React\Socket\Server(8080); +$second = new React\Socket\SocketServer('127.0.0.1:8080'); ``` > Note that these error conditions may vary depending on your system and/or @@ -402,17 +404,11 @@ $second = new React\Socket\Server(8080); See the exception message and code for more details about the actual error condition. -This class takes an optional `LoopInterface|null $loop` parameter that can be used to -pass the event loop instance to use for this object. You can use a `null` value -here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). -This value SHOULD NOT be given unless you're sure you want to explicitly use a -given event loop instance. - Optionally, you can specify [TCP socket context options](https://www.php.net/manual/en/context.socket.php) for the underlying stream socket resource like this: ```php -$server = new React\Socket\Server('[::1]:8080', null, array( +$socket = new React\Socket\SocketServer('[::1]:8080', array( 'tcp' => array( 'backlog' => 200, 'so_reuseport' => true, @@ -426,8 +422,6 @@ $server = new React\Socket\Server('[::1]:8080', null, array( and/or PHP version. Passing unknown context options has no effect. The `backlog` context option defaults to `511` unless given explicitly. - For BC reasons, you can also pass the TCP socket context options as a simple - array without wrapping this in another array under the `tcp` key. You can start a secure TLS (formerly known as SSL) server by simply prepending the `tls://` URI scheme. @@ -438,7 +432,7 @@ which in its most basic form may look something like this if you're using a PEM encoded certificate file: ```php -$server = new React\Socket\Server('tls://127.0.0.1:8080', null, array( +$socket = new React\Socket\SocketServer('tls://127.0.0.1:8080', array( 'tls' => array( 'local_cert' => 'server.pem' ) @@ -454,7 +448,7 @@ If your private key is encrypted with a passphrase, you have to specify it like this: ```php -$server = new React\Socket\Server('tls://127.0.0.1:8000', null, array( +$socket = new React\Socket\SocketServer('tls://127.0.0.1:8000', array( 'tls' => array( 'local_cert' => 'server.pem', 'passphrase' => 'secret' @@ -467,7 +461,7 @@ SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you want to negotiate with the remote side: ```php -$server = new React\Socket\Server('tls://127.0.0.1:8000', null, array( +$socket = new React\Socket\SocketServer('tls://127.0.0.1:8000', array( 'tls' => array( 'local_cert' => 'server.pem', 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER @@ -488,7 +482,7 @@ Whenever a client connects, it will emit a `connection` event with a connection instance implementing [`ConnectionInterface`](#connectioninterface): ```php -$server->on('connection', function (React\Socket\ConnectionInterface $connection) { +$socket->on('connection', function (React\Socket\ConnectionInterface $connection) { echo 'Plaintext connection from ' . $connection->getRemoteAddress() . PHP_EOL; $connection->write('hello there!' . PHP_EOL); @@ -498,10 +492,20 @@ $server->on('connection', function (React\Socket\ConnectionInterface $connection See also the [`ServerInterface`](#serverinterface) for more details. -> Note that the `Server` class is a concrete implementation for TCP/IP sockets. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + +> Note that the `SocketServer` class is a concrete implementation for TCP/IP sockets. If you want to typehint in your higher-level protocol implementation, you SHOULD use the generic [`ServerInterface`](#serverinterface) instead. +> Changelog v1.9.0: This class has been added with an improved constructor signature + as a replacement for the previous `Server` class in order to avoid any ambiguities. + The previous name has been deprecated and should not be used anymore. + ### Advanced server usage #### TcpServer diff --git a/examples/01-echo-server.php b/examples/01-echo-server.php index 8a729009..1ec645de 100644 --- a/examples/01-echo-server.php +++ b/examples/01-echo-server.php @@ -3,7 +3,7 @@ // Just start this server and connect to it. Everything you send to it will be // sent back to you. // -// $ php examples/01-echo-server.php 8000 +// $ php examples/01-echo-server.php 127.0.0.1:8000 // $ telnet localhost 8000 // // You can also run a secure TLS echo server like this: @@ -16,22 +16,19 @@ // $ php examples/01-echo-server.php unix:///tmp/server.sock // $ nc -U /tmp/server.sock -use React\Socket\Server; -use React\Socket\ConnectionInterface; - require __DIR__ . '/../vendor/autoload.php'; -$server = new Server(isset($argv[1]) ? $argv[1] : 0, null, array( +$socket = new React\Socket\SocketServer(isset($argv[1]) ? $argv[1] : '127.0.0.1:0', array( 'tls' => array( 'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem') ) )); -$server->on('connection', function (ConnectionInterface $connection) { +$socket->on('connection', function (React\Socket\ConnectionInterface $connection) { echo '[' . $connection->getRemoteAddress() . ' connected]' . PHP_EOL; $connection->pipe($connection); }); -$server->on('error', 'printf'); +$socket->on('error', 'printf'); -echo 'Listening on ' . $server->getAddress() . PHP_EOL; +echo 'Listening on ' . $socket->getAddress() . PHP_EOL; diff --git a/examples/02-chat-server.php b/examples/02-chat-server.php index ede541d9..9027f28b 100644 --- a/examples/02-chat-server.php +++ b/examples/02-chat-server.php @@ -3,7 +3,7 @@ // Just start this server and connect with any number of clients to it. // Everything a client sends will be broadcasted to all connected clients. // -// $ php examples/02-chat-server.php 8000 +// $ php examples/02-chat-server.php 127.0.0.1:8000 // $ telnet localhost 8000 // // You can also run a secure TLS chat server like this: @@ -16,23 +16,19 @@ // $ php examples/02-chat-server.php unix:///tmp/server.sock // $ nc -U /tmp/server.sock -use React\Socket\Server; -use React\Socket\ConnectionInterface; -use React\Socket\LimitingServer; - require __DIR__ . '/../vendor/autoload.php'; -$server = new Server(isset($argv[1]) ? $argv[1] : 0, null, array( +$socket = new React\Socket\SocketServer(isset($argv[1]) ? $argv[1] : '127.0.0.1:0', array( 'tls' => array( 'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem') ) )); -$server = new LimitingServer($server, null); +$socket = new React\Socket\LimitingServer($socket, null); -$server->on('connection', function (ConnectionInterface $client) use ($server) { +$socket->on('connection', function (React\Socket\ConnectionInterface $client) use ($socket) { // whenever a new message comes in - $client->on('data', function ($data) use ($client, $server) { + $client->on('data', function ($data) use ($client, $socket) { // remove any non-word characters (just for the demo) $data = trim(preg_replace('/[^\w\d \.\,\-\!\?]/u', '', $data)); @@ -43,12 +39,12 @@ // prefix with client IP and broadcast to all connected clients $data = trim(parse_url($client->getRemoteAddress(), PHP_URL_HOST), '[]') . ': ' . $data . PHP_EOL; - foreach ($server->getConnections() as $connection) { + foreach ($socket->getConnections() as $connection) { $connection->write($data); } }); }); -$server->on('error', 'printf'); +$socket->on('error', 'printf'); -echo 'Listening on ' . $server->getAddress() . PHP_EOL; +echo 'Listening on ' . $socket->getAddress() . PHP_EOL; diff --git a/examples/03-http-server.php b/examples/03-http-server.php index 5b96646c..cc6440fb 100644 --- a/examples/03-http-server.php +++ b/examples/03-http-server.php @@ -12,7 +12,7 @@ // // Just start this server and send a request to it: // -// $ php examples/03-http-server.php 8000 +// $ php examples/03-http-server.php 127.0.0.1:8000 // $ curl -v http://localhost:8000/ // $ ab -n1000 -c10 http://localhost:8000/ // $ docker run -it --rm --net=host jordi/ab ab -n1000 -c10 http://localhost:8000/ @@ -29,24 +29,21 @@ // $ php examples/03-http-server.php unix:///tmp/server.sock // $ nc -U /tmp/server.sock -use React\Socket\Server; -use React\Socket\ConnectionInterface; - require __DIR__ . '/../vendor/autoload.php'; -$server = new Server(isset($argv[1]) ? $argv[1] : 0, null, array( +$socket = new React\Socket\SocketServer(isset($argv[1]) ? $argv[1] : '127.0.0.1:0', array( 'tls' => array( 'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem') ) )); -$server->on('connection', function (ConnectionInterface $connection) { +$socket->on('connection', function (React\Socket\ConnectionInterface $connection) { $connection->once('data', function () use ($connection) { $body = "