edefimov / async-sockets
Library for asynchronous work with sockets based on php streams
Installs: 1 188
Dependents: 0
Suggesters: 0
Security: 0
Stars: 45
Watchers: 6
Forks: 4
Open Issues: 2
Requires
- php: >=5.4
Requires (Dev)
- symfony/console: ~2.7 || ~3.0
- symfony/event-dispatcher: ~2.7 || ~3.0
- symfony/yaml: ~2.7 || ~3.0
Suggests
- ext-libevent: For using RequestExecutor engine based on libevent
- symfony/event-dispatcher: Allows to notify system about socket events
This package is auto-updated.
Last update: 2024-12-09 02:06:10 UTC
README
Async sockets is event-based library for asynchronous work with sockets built on php streams.
Features
- multiple requests execution at once
- distinguish frame boundaries
- server socket support
- persistent connections support
- multiple persistent connections to the same host:port
- processing TLS handshake asynchronous
- synchronization between sockets
- determine datagram size for UDP sockets
- all transports returned by stream_get_transports are supported
- compatible with symfony event dispatcher component
- full control over timeouts
- dynamically adding new request during execution process
- separate timeout values for each socket
- custom sockets setup by php stream contexts
- custom user context for each socket
- stop request either for certain socket or for all of them
- strategies for limiting number of running requests
- error handling is based on exceptions
- supports libevent engine
What is it for
Async sockets library provides networking layer for applications, hides complexity of I/O operations, and cares about connections management. The library will be a powerful base for implementing arbitrary networking protocol as for implementing server on PHP. Running multiple requests at once decreases delay of I/O operation to the size of timeout assigned to the slowest server.
Documentation
Installation
The recommended way to install async sockets library is through composer
stable version:
$ composer require edefimov/async-sockets:~0.3.0 --prefer-dist|--prefer-source
actual version:
$ composer require edefimov/async-sockets:dev-master
Use --prefer-dist
option in production environment, so as it ignores downloading of test and demo files,
and --prefer-source
option for development. Development version includes both test and demo files.
Quick start
Step 1. Create AsyncSocketFactory
at point where you want to start request
$factory = new AsyncSocketFactory();
Step 2. Create RequestExecutor and proper amount of sockets
$client = $factory->createSocket(AsyncSocketFactory::SOCKET_CLIENT); $anotherClient = $factory->createSocket(AsyncSocketFactory::SOCKET_CLIENT); $executor = $factory->createRequestExecutor();
Step 3. Create event handler with events, you are interested in
$handler = new CallbackEventHandler( [ EventType::INITIALIZE => [$this, 'onInitialize'], EventType::CONNECTED => [$this, 'onConnected'], EventType::WRITE => [$this, 'onWrite'], EventType::READ => [$this, 'onRead'], EventType::ACCEPT => [$this, 'onAccept'], EventType::DATA_ALERT => [$this, 'onDataAlert'], EventType::DISCONNECTED => [$this, 'onDisconnected'], EventType::FINALIZE => [$this, 'onFinalize'], EventType::EXCEPTION => [$this, 'onException'], EventType::TIMEOUT => [$this, 'onTimeout'], ] );
Step 4. Add sockets into RequestExecutor
$executor->socketBag()->addSocket( $client, new WriteOperation(), [ RequestExecutorInterface::META_ADDRESS => 'tls://github.com:443', RequestExecutorInterface::META_CONNECTION_TIMEOUT => 30, RequestExecutorInterface::META_IO_TIMEOUT => 5, ], $handler ); $executor->socketBag()->addSocket( $anotherClient, new WriteOperation(), [ RequestExecutorInterface::META_ADDRESS => 'tls://packagist.org:443', RequestExecutorInterface::META_CONNECTION_TIMEOUT => 10, RequestExecutorInterface::META_IO_TIMEOUT => 2, ], $handler );
Step 5. Execute it!
$executor->executeRequest();
Example usage
Client socket
$factory = new AsyncSocketFactory(); $client = $factory->createSocket(AsyncSocketFactory::SOCKET_CLIENT); $anotherClient = $factory->createSocket(AsyncSocketFactory::SOCKET_CLIENT); $executor = $factory->createRequestExecutor(); $handler = new CallbackEventHandler( [ EventType::INITIALIZE => [$this, 'onInitialize'], EventType::CONNECTED => [$this, 'onConnected'], EventType::WRITE => [$this, 'onWrite'], EventType::READ => [$this, 'onRead'], EventType::DISCONNECTED => [$this, 'onDisconnected'], EventType::FINALIZE => [$this, 'onFinalize'], EventType::EXCEPTION => [$this, 'onException'], EventType::TIMEOUT => [$this, 'onTimeout'], ] ); $executor->socketBag()->addSocket( $client, new WriteOperation(), [ RequestExecutorInterface::META_ADDRESS => 'tls://github.com:443', RequestExecutorInterface::META_CONNECTION_TIMEOUT => 30, RequestExecutorInterface::META_IO_TIMEOUT => 5, ], $handler ); $executor->socketBag()->addSocket( $anotherClient, new WriteOperation(), [ RequestExecutorInterface::META_ADDRESS => 'tls://packagist.org:443', RequestExecutorInterface::META_CONNECTION_TIMEOUT => 10, RequestExecutorInterface::META_IO_TIMEOUT => 2, ], $handler ); $executor->executeRequest();
See full example here
Server socket
$factory = new AsyncSocketFactory(); $serverSocket = $factory->createSocket(AsyncSocketFactory::SOCKET_SERVER); $executor = $factory->createRequestExecutor(); $executor->socketBag()->addSocket( $serverSocket, new ReadOperation(), [ RequestExecutorInterface::META_ADDRESS => "tcp://localhost:10280", // or "udp://localhost:10280" RequestExecutorInterface::META_CONNECTION_TIMEOUT => RequestExecutorInterface::WAIT_FOREVER, RequestExecutorInterface::META_IO_TIMEOUT => RequestExecutorInterface::WAIT_FOREVER, ], new CallbackEventHandler( [ EventType::ACCEPT => function (AcceptEvent $event){ $event->getExecutor()->socketBag()->addSocket( $event->getClientSocket(), new ReadOperation(), [ ], // client handlers ); } ] ) ); $executor->executeRequest();
See full example here