spatie/simple-tcp-client
Simple TCP client for PHP/Laravel: connect to a host/port, send data, and receive responses with a clean API. Useful for interacting with TCP services (SMTP, HTTP, custom servers), testing network protocols, and building lightweight clients.
Installation:
composer require spatie/simple-tcp-client
No additional configuration is required—just autoload the package.
First Use Case: Connect to a TCP server (e.g., SMTP, FTP, or a custom service) and exchange data:
use Spatie\SimpleTcpClient\TcpClient;
$client = new TcpClient('host.example.com', 1234);
$client->connect();
// Send a command (e.g., SMTP EHLO)
$client->send("EHLO example.com\r\n");
// Receive response
$response = $client->receive();
echo $response; // Parse server response
$client->close();
Where to Look First:
TcpClient class: Core functionality for connections, sending/receiving data.connect()/close(): Manage connection lifecycle.send()/receive(): Core methods for TCP communication.Connection Management:
try-catch with connect() to handle connection failures gracefully:
try {
$client->connect();
// Proceed with communication
} catch (\Spatie\SimpleTcpClient\Exceptions\ConnectionFailed $e) {
Log::error("TCP connection failed: " . $e->getMessage());
}
Protocol-Specific Workflows:
send()/receive() calls for multi-step protocols:
$client->send("AUTH LOGIN\r\n");
$client->send(base64_encode($username) . "\r\n");
$client->send(base64_encode($password) . "\r\n");
sendRaw() for non-text protocols (e.g., FTP, custom binary APIs):
$client->sendRaw($binaryPayload);
Timeout Handling:
$client = new TcpClient('host.example.com', 1234, [
'timeout' => 5.0, // 5 seconds
]);
Reusable Client Instances:
TcpClient:
$client = new TcpClient('host.example.com', 8080);
$client->connect();
while ($data = $client->receive()) {
// Process data in a loop
}
Integration with Laravel:
dispatch(new SendTcpCommandJob($host, $port, $payload));
$this->app->bind(TcpClient::class, function ($app) {
return new TcpClient(config('tcp.host'), config('tcp.port'));
});
Testing:
TcpClient in unit tests using Laravel’s Mockery:
$mock = Mockery::mock(TcpClient::class);
$mock->shouldReceive('receive')->andReturn('220 Ready');
Connection State:
send()/receive() without connect() throws exceptions. Always verify the connection state:
if (!$client->isConnected()) {
$client->connect();
}
try-catch blocks or check isConnected() before operations.Timeouts:
setTimeout():
$client->setTimeout(30.0); // 30 seconds
Buffering Issues:
receive() may return partial data if the server sends responses in chunks.\r\n) or EOF:
$response = '';
while (($chunk = $client->receive()) && strpos($chunk, "\r\n") === false) {
$response .= $chunk;
}
Resource Leaks:
close() can lead to open sockets consuming resources.finally block or Laravel’s illuminate/support/Traits/ManagesFluentMethods for automatic cleanup:
try {
$client->connect();
// ...
} finally {
$client->close();
}
Protocol-Specific Delimiters:
private function parseSmtpResponse(string $response): array {
return explode("\r\n", $response);
}
Logging:
send()/receive() data for debugging:
Log::debug('TCP Send:', ['data' => $payload]);
Log::debug('TCP Receive:', ['data' => $response]);
Configuration:
config/tcp.php for easy maintenance:
return [
'host' => env('TCP_HOST', 'localhost'),
'port' => env('TCP_PORT', 1234),
'timeout' => 10.0,
];
Extending Functionality:
class TcpProtocolException extends \Spatie\SimpleTcpClient\Exceptions\ConnectionException {}
TcpClient to add retries or logging:
class LoggingTcpClient extends TcpClient {
public function send(string $data) {
Log::info('Sending: ' . $data);
return parent::send($data);
}
}
Performance:
connect()/close() calls by reusing connections.sendRaw() for binary data to avoid encoding overhead.Security:
if (!preg_match('/^[A-Za-z0-9\s]+$/', $response)) {
throw new \InvalidArgumentException("Invalid server response");
}
Testing:
spatie/fake-server to simulate TCP servers in tests:
$fakeServer = new FakeServer();
$fakeServer->onReceive(fn ($data) => "ACK $data");
$client->connect($fakeServer->getHost(), $fakeServer->getPort());
How can I help you explore Laravel packages today?