moebius / socket
基于协程的socket客户端和服务器实现。
Requires
- charm/event: >=1.0.0
- charm/options: >=1.0.6
- moebius/coroutine: >=1.0
Requires (Dev)
- charm/testing: >=0.0.8
This package is auto-updated.
Last update: 2024-09-20 03:08:03 UTC
README
一个易于使用的接口,用于处理多个同时存在的非阻塞网络连接。
注意!PHP的默认构建限制了并发“轮询”连接的数量为1024。可以通过运行多个服务器进程或重新编译PHP来克服此限制。
架构
此库提供了三个核心类,您可以使用这些类创建网络客户端或服务器实现。
-
Moebius\Socket\Client
提供了PHP中stream_socket_client()
函数的API,并可用于创建并发HTTP客户端。 -
Moebius\Socket\Server
提供了stream_socket_server()
函数的API,允许您创建接受连接的服务器,并为每个新连接的客户端提供连接实例。 -
Moebius\Socket\Connection
与客户端类类似,但连接由外部发起并由服务器类返回。
示例客户端
use Moebius\Socket\Client; use function M\{go, await}; /** * *** COROUTINE 1 *** */ $google = go(function() { $client = new Client('tcp://www.google.com:80'); $client->write("GET / HTTP/1.0\r\n\r\n"); while (!$client->eof()) { echo "< ".$client->readLine()."\n"; } }); /** * *** COROUTINE 2 *** */ $bing = go(function() { $client = new Client('tcp://www.bing.com:80'); $client->write("GET / HTTP/1.0\r\n\r\n"); while (!$client->eof()) { echo "< ".$client->readLine()."\n"; } }); /** * *** AWAIT BOTH COROUTINES *** */ await($google); await($bing);
示例服务器
use Moebius\Socket\Server; use function M\go; $server = new Server('tcp://0.0.0.0:8080'); while ($connection = $server->accept()) { /** * *** LAUNCH A COROUTINE PER CONNECTION *** */ go(function() use ($connection) { $requestLine = $connection->readLine(); do { $header = $connection->readLine(); } while ($header !== ''); $connection->write(<<<RESPONSE HTTP/1.0 200 OK\r Content-Type: text/plain\r \r Hello World! RESPONSE); $connection->close(); }); }
完整工作示例
要发出多个并发请求,您只需通过 M\go(callable $callback)
函数运行您的代码。这样,您可以同时执行许多请求。
<?php require(__DIR__.'/../vendor/autoload.php'); use Moebius\Socket\Client; use function M\{go, await}; // Asynchronous operation requires that you call via the `go()` function. $futureBufferA = go(function() { $client = new Client('tcp://www.dagbladet.no:80'); $client->connect(); $client->write("GET / HTTP/1.0\r\n\r\n"); $buffer = '' while (!$client->eof()) { $buffer .= $client->read(4096); } return $buffer; }); $futureBufferA = go(function() { $client = new Client('tcp://www.vg.no:80'); $client->connect(); $client->write("GET / HTTP/1.0\r\n\r\n"); $buffer = '' while (!$client->eof()) { $buffer .= $client->read(4096); } return $buffer; }); // note that it does not matter which order you await each of these buffers $bufferA = await( $futureBufferA ); $bufferB = await( $futureBufferB ); echo "Received ".strlen($bufferA)." bytes from client A and ".strlen($bufferB)." bytes from client B\n";
API
-
Client::__construct(string $address, ClientOptions|array $options=[])
。创建一个socket客户端实例,但不会执行任何网络操作。 -
Client::connect()
。非阻塞连接到服务器。(DNS查找操作可能会暂时阻塞) -
Client::disconnect()
。关闭连接。 -
Client::read(int $length): string
。从服务器读取$length
字节。如果您想发出多个请求,可能需要通过M\go(callable $coroutine)
函数执行此操作。