# AMPHP v3 — WebSocket Patterns > **Import note**: `WebsocketClient` is in `amphp/websocket` (`Amp\Websocket`), NOT in `amphp/websocket-server`. --- ## Echo Server (receive → reply) ```php receive()) { // null = client disconnected $client->sendText($message->buffer()); // sendText() or sendBinary() } } }, ); $router->addRoute('GET', '/ws', $websocket); ``` --- ## Push-Only Pattern (server pushes, drains receive buffer) Not draining incoming messages causes receive buffer overflow and deadlock. ```php isClosed()) { $client->sendText(json_encode( ['time' => date('Y-m-d H:i:s'), 'timestamp' => time()], JSON_THROW_ON_ERROR, )); delay($this->interval); } }); // REQUIRED: drain incoming messages to prevent buffer deadlock while ($client->receive() !== null) { // ignore client messages } // Client disconnected — suppress unhandled errors from the sender fiber $sender->ignore(); } }; ``` --- ## Broadcast Gateway (push to all connected clients) ```php gateway->addClient($client); while ($message = $client->receive()) { // Broadcast incoming message to ALL connected clients $this->gateway->broadcastText($message->buffer()); } } }; // Push server-side event from anywhere: $gateway->broadcastText(json_encode(['type' => 'update', 'data' => $payload], JSON_THROW_ON_ERROR)); ``` --- ## WebSocket Client (amphp/websocket-client) ```php withHeader('Authorization', 'Bearer ' . $token); $connection = $connector->connect($handshake, new TimeoutCancellation(10.0)); $connection->sendText('Hello, Server!'); while ($message = $connection->receive()) { echo $message->buffer() . "\n"; if ($message->buffer() === 'bye') { break; } } $connection->close(); ``` --- ## Streaming Large Binary WebSocket Messages ```php connect(new WebsocketHandshake('wss://stream.example.com')); while ($message = $connection->receive()) { if ($message->isBinary()) { // Stream large binary payload without buffering all at once while (null !== $chunk = $message->read()) { processBinaryChunk($chunk); } } else { handleText($message->buffer()); } } ``` --- ## Key Rules - `WebsocketClient` → `Amp\Websocket\WebsocketClient` (from `amphp/websocket`) - `WebsocketClientHandler`, `Websocket`, `AllowOriginAcceptor` → `Amp\Websocket\Server\*` - Push-only handlers **must** drain incoming messages to prevent deadlock - After the receive loop exits, call `$sender->ignore()` to suppress abandoned-fiber errors - `addClient()` in `WebsocketClientGateway` automatically removes clients on disconnect