matasarei / phptcp
A TCP client for PHP
Requires
- php: >=7.4
- psr/log: ^1.1 || ^2.0 || ^3.0
Requires (Dev)
- phpunit/phpunit: ^9.6
This package is auto-updated.
Last update: 2026-07-23 21:24:00 UTC
README
A lightweight TCP client for PHP with no runtime dependencies beyond a PSR-3 logger interface. It wraps PHP's native stream functions in a small, testable API: pluggable socket transports, configurable timeouts, optional delimiter-based response framing and PSR-3 logging.
Well suited for simple text-based request/response protocols — line-delimited JSON, JSON-RPC over TCP, custom device or legacy service protocols, and similar.
Features
- Simple connect / request / disconnect API over plain TCP
- Two built-in transports —
StreamSocket(stream_socket_client) andFSocket(fsockopen) — plus a one-methodSocketInterfacefor custom transports - Optional end-of-response delimiter for line-based protocols (see Response framing)
- Detects broken streams and connections closed by the peer; completes partial writes
- Configurable connection, request and read timeouts
- PSR-3 (
psr/logv1, v2 or v3) logger support for debugging
Requirements
- PHP 7.4 or newer
Installation
composer require matasarei/phptcp
Quick start
use Matasar\PhpTcp\Client; use Matasar\PhpTcp\Request; use Matasar\PhpTcp\Socket\StreamSocket; $client = new Client('ip_or_hostname', 8888, new StreamSocket()); $client->connect(); $response = $client->request(new Request('request data')); $client->disconnect(); var_dump($response->getData());
Request accepts an optional per-request timeout in seconds (default 30):
$request = new Request('request data', 5);
Socket transports
The library includes two transports: StreamSocket and FSocket.
The difference is stream_socket_client() vs fsockopen() under the hood;
pick whichever you prefer, or implement Socket\SocketInterface to supply your own
(e.g. for TLS wrappers or unit-test stubs).
Both transports accept a blocking timeout (seconds, default 1) that controls how long a single read waits for data before reporting "no data yet":
use Matasar\PhpTcp\Socket\FSocket; new FSocket(2); // wait up to 2 seconds per read cycle new FSocket(0); // non-blocking mode
Client settings
use Matasar\PhpTcp\Client; use Matasar\PhpTcp\Socket\FSocket; $client = new Client('hostname', 1234, new FSocket()); $client->setChunkSize(16384); // read data by 16 KB per cycle (default 8 KB). $client->setPollInterval(5000); // wait 5 ms between data availability checks (default 1 ms). $client->setDelimiter("\n"); // treat "\n" as the end of a response (see below). $client->setLogger(new PsrLogger()); // any PSR-3 logger, for debugging. $client->connect(5); // connection timeout in seconds (default 2).
Response framing
By default, the client considers a response complete when the server stops sending data for a moment (a silent interval on the stream). This works without any protocol knowledge, but it has two downsides: every read costs an extra blocking-timeout interval, and a server that stalls mid-response can have its reply cut short.
If your protocol marks the end of a message — like line-based protocols such as JSON-RPC over TCP — set a delimiter instead:
$client->setDelimiter("\n");
With a delimiter set, the client returns as soon as the response ends with the delimiter
(the delimiter is kept in the response data). It throws a RequestException if a complete
response does not arrive within the request timeout, and a ConnectionException if the
connection is closed before the response is completed.
Error handling
All exceptions live under Matasar\PhpTcp\Exception:
| Exception | Thrown when |
|---|---|
ConnectionException |
Connection could not be established, is already open, was closed by the peer, or the stream broke mid-transfer. |
RequestException |
No (or no complete) response arrived within the request timeout. |
SocketException |
Low-level transport failure; wrapped into ConnectionException by connect(). |
use Matasar\PhpTcp\Exception\ConnectionException; use Matasar\PhpTcp\Exception\RequestException; try { $client->connect(); $response = $client->request($request); } catch (ConnectionException $exception) { // failed to connect / connection lost } catch (RequestException $exception) { // the server did not respond in time }
Testing
The test suite runs against PHP 7.4–8.5 in CI.
Locally, the easiest way is Docker — no PHP or Composer installation required:
docker run --rm -v $(pwd):/app -w /app composer:lts composer install docker run --rm -v $(pwd):/app -w /app composer:lts vendor/bin/phpunit
Or with a local PHP setup:
composer install vendor/bin/phpunit
License
Released under the MIT license.