Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/amphp/socket
Non-blocking socket and TLS functionality for PHP based on Amp.
https://github.com/amphp/socket
amphp async client io non-blocking php server socket ssl tcp tls udp unix
Last synced: 3 months ago
JSON representation
Non-blocking socket and TLS functionality for PHP based on Amp.
- Host: GitHub
- URL: https://github.com/amphp/socket
- Owner: amphp
- License: mit
- Created: 2014-07-31T17:57:14.000Z (over 10 years ago)
- Default Branch: 2.x
- Last Pushed: 2024-04-21T14:41:57.000Z (7 months ago)
- Last Synced: 2024-05-15T17:49:16.656Z (6 months ago)
- Topics: amphp, async, client, io, non-blocking, php, server, socket, ssl, tcp, tls, udp, unix
- Language: PHP
- Homepage: https://amphp.org/socket
- Size: 1.04 MB
- Stars: 214
- Watchers: 14
- Forks: 39
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# amphp/socket
AMPHP is a collection of event-driven libraries for PHP designed with fibers and concurrency in mind.
`amphp/socket` is a library for establishing and encrypting non-blocking sockets.
It provides a socket abstraction for clients and servers.
It abstracts the really low levels of non-blocking streams in PHP.[![Latest Release](https://img.shields.io/github/release/amphp/socket.svg?style=flat-square)](https://github.com/amphp/socket/releases)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/amphp/socket/blob/master/LICENSE)## Installation
This package can be installed as a [Composer](https://getcomposer.org/) dependency.
```bash
composer require amphp/socket
```## Requirements
`amphp/socket` heavily relies on `amphp/byte-stream`, specifically its `ReadableStream` and `WritableStream` interfaces.
## Connecting to a Server
`amphp/socket` allows clients to connect to servers via TCP, UDP, or Unix domain sockets.
You can establish a socket connection using `Amp\Socket\connect()`.
It will automatically resolve DNS names and retries other IPs if a connection fails and multiple IPs are available.```php
// You can customize connect() options using ConnectContext
$connectContext = (new Amp\Socket\ConnectContext)
->withConnectTimeout(5);// You can optionally pass a Cancellation object to cancel a pending connect() operation
$deferredCancellation = new Amp\DeferredCancellation();$socket = connect('amphp.org:80', $connectContext, $deferredCancellation->getCancellation());
```### Encrypted Connections / TLS
If you want to connect via TLS, use `Amp\Socket\connectTls()` instead or call `$socket->setupTls()` on the returned socket.
### Handling Connections
`Socket` implements `ReadableStream` and `WritableStream`, so everything from [`amphp/byte-stream`](https://v3.amphp.org/byte-stream) applies for receiving and sending data.
```php
#!/usr/bin/env php
write('Usage: examples/simple-http-client.php ' . PHP_EOL);
exit(1);
}$uri = Http::createFromString($argv[1]);
$host = $uri->getHost();
$port = $uri->getPort() ?? ($uri->getScheme() === 'https' ? 443 : 80);
$path = $uri->getPath() ?: '/';$connectContext = (new ConnectContext)
->withTlsContext(new ClientTlsContext($host));$socket = $uri->getScheme() === 'http'
? connect($host . ':' . $port, $connectContext)
: connectTls($host . ':' . $port, $connectContext);$socket->write("GET {$path} HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n");
ByteStream\pipe($socket, $stdout);
```## Server
`amphp/socket` allows listening for incoming TCP connections as well as connections via Unix domain sockets.
It defaults to secure TLS settings if you decide to enable TLS.### Listening and Accepting Connections
Use `Amp\Socket\Socket\listen()` to listen on a port or unix domain socket.
It's a wrapper around `stream_socket_server` that gives useful error message on failures via exceptions.Once you're listening, accept clients using `Server::accept()`.
It returns a `Socket` that returns once a new client has been accepted.
It's usually called within a `while` loop:```php
$server = Socket\listen("tcp://127.0.0.1:1337");while ($client = $server->accept()) {
// You shouldn't spend too much time here, because that blocks accepting another client, so we use async():
async(function () use ($client) {
// Handle client connection here
});
}
```### Handling Connections
`Socket` implements `ReadableStream` and `WritableStream`, so everything from [`amphp/byte-stream`](https://v3.amphp.org/byte-stream) applies for receiving and sending data.
It's best to handle clients in their own coroutine, while letting the server accept all clients as soon as there are new clients.```php
#!/usr/bin/env php
getAddress() . ' ...' . PHP_EOL;
echo 'Open your browser and visit http://' . $server->getAddress() . '/' . PHP_EOL;while ($socket = $server->accept()) {
async(function () use ($socket) {
$address = $socket->getRemoteAddress();
$ip = $address->getHost();
$port = $address->getPort();echo "Accepted connection from {$address}." . PHP_EOL;
$body = "Hey, your IP is {$ip} and your local port used is {$port}.";
$bodyLength = \strlen($body);$socket->write("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: {$bodyLength}\r\n\r\n{$body}");
$socket->end();
});
}
```### Closing Connections
Once you're done with a client, close the connection using `Socket::close()`.
If you want to wait for all data to be successfully written before closing the connection, use `Socket::end()`.
See above for an example.### Server Address
Sometimes you don't know the address the server is listening on, e.g. because you listed to `tcp://127.0.0.1:0`, which assigns a random free port. You can use `Server::getAddress()` to get the address the server is bound to.
### Server Shutdown
Once you're done with the server socket, close the socket.
That means, the server won't listen on the specified location anymore.
Use `Server::close()` to close the server socket.### Encrypted Connections / TLS
As already mentioned in the documentation for `Amp\Socket\Socket\listen()`, you need to enable TLS manually after accepting connections.
For a TLS server socket, you listen on the `tcp://` protocol on a specified address.
After accepting clients, call `$socket->setupTls()` where `$socket` is the socket returned from `SocketServer::accept()`.> **Warning**
> Any data transmitted before `Socket::setupTls()` completes will be transmitted in clear text.
> Don't attempt to read from the socket or write to it manually.
> Doing so will read the raw TLS handshake data that's supposed to be read by OpenSSL.#### Self-Signed Certificates
There's no option to allow self-signed certificates in `ClientTlsContext` since it is no more secure than disabling peer verification.
To safely use a self-signed certificate, disable peer verification and require fingerprint verification of the certificate using `ClientTlsContext::withPeerFingerprint()`.## Security
If you discover any security related issues, please email [`[email protected]`](mailto:[email protected]) instead of using the issue tracker.
## License
The MIT License (MIT). Please see [`LICENSE`](./LICENSE) for more information.