icicleio / websocket
Icicle 的异步 WebSocket 组件。
v0.1.0
2016-03-11 17:08 UTC
Requires
- icicleio/http: ^0.3
- icicleio/icicle: ^0.9.1
- icicleio/log: ^0.1
- icicleio/socket: ^0.5.2
- paragonie/random_compat: ^1
Requires (Dev)
- phpunit/phpunit: ^4.8
- symfony/yaml: ^2.7
This package is auto-updated.
Last update: 2024-09-14 02:40:18 UTC
README
异步、非阻塞 WebSocket 服务器。
该库是 Icicle 的组件,提供异步 WebSocket 服务器,可以处理同一端口的常规 HTTP 请求和 WebSocket 请求。与其他 Icicle 组件类似,此库使用从 Awaitables 和 Generators 构建的 Coroutines,使得编写异步代码更像编写同步代码。
文档和支持
要求
- PHP 5.5+ 对 v0.1.x 分支(当前稳定)和 v1.x 分支(镜像当前稳定)
- PHP 7 对 v2.0(master)分支支持生成器委托和返回表达式
建议
- openssl 扩展:创建安全 WebSocket 服务器所必需。
安装
推荐的安装方式是使用 Composer 包管理器。(有关安装和使用的更多信息,请参阅 Composer 安装指南。)
运行以下命令以在项目中使用此库
composer require icicleio/websocket
您也可以手动编辑 composer.json
以将此库作为项目要求添加。
// composer.json { "require": { "icicleio/websocket": "^0.1" } }
示例
以下示例创建了一个简单的 HTTP 服务器,它接受在路径 /echo
上的 WebSocket 连接,否则在其他路径上以 404 状态码响应。
#!/usr/bin/env php <?php require '/vendor/autoload.php'; use Icicle\Http\Message\{BasicResponse, Request, Response}; use Icicle\Http\Server\RequestHandler; use Icicle\Loop; use Icicle\Socket\Socket; use Icicle\WebSocket\{Application, Connection, Server\Server}; $echo = new class implements Application { /** * {@inheritdoc} */ public function onHandshake(Response $response, Request $request, Socket $socket): Response { // This method provides an opportunity to inspect the Request and Response before a connection is accepted. // Cookies may be set and returned on a new Response object, e.g.: return $response->withCookie(...); return $response; // No modification needed to the response, so the passed Response object is simply returned. } /** * {@inheritdoc} */ public function onConnection(Connection $connection, Response $response, Request $request): Generator { // The Response and Request objects used to initiate the connection are provided for informational purposes. // This method will primarily interact with the Connection object. yield from $connection->send('Connected to echo WebSocket server powered by Icicle.'); // Messages are read through an Observable that represents an asynchronous set. There are a variety of ways // to use this asynchronous set, including an asynchronous iterator as shown in the example below. $observable = $connection->read(); // Connection::read() returns an observable of received Message objects. $iterator = $observable->getIterator(); while (yield from $iterator->isValid()) { /** @var \Icicle\WebSocket\Message $message */ $message = $iterator->getCurrent(); if ($message->getData() === 'close') { yield from $connection->close(); // Close the connection if the message contains only 'close' } else { yield from $connection->send($message); // Echo the message back to the client. } } /** @var \Icicle\WebSocket\Close $close */ $close = $iterator->getReturn(); // Only needs to be called if the close reason is needed. } }; $server = new Server(new class ($echo) implements RequestHandler { /** @var \Icicle\WebSocket\Application */ private $application; public function __construct(Application $application) { $this->application = $application; } public function onRequest(Request $request, Socket $socket): Generator { if ($request->getUri()->getPath() === '/echo') { return $this->application; // Return a WebSocket Application to create a WebSocket connection. } $response = new BasicResponse(Response::NOT_FOUND, [ 'Content-Type' => 'text/plain', ]); yield from $response->getBody()->end('Resource not found.'); return $response; // Return a regular HTTP response for other request paths. } public function onError(int $code, Socket $socket): Response { return new BasicResponse($code); } }); $server->listen(8080); Loop\run();