icicleio/socket

为 Icicle 提供的异步流套接字服务器和客户端。

v0.5.3 2015-12-30 05:41 UTC

README

这个库是 Icicle 的组件,提供异步流套接字服务器、连接器和数据报。与其他 Icicle 组件一样,这个库使用从 可等待生成器 构建的自定义协程,使得编写异步代码更像编写同步代码。

Build Status Coverage Status Semantic Version MIT License @icicleio on Twitter

要求
  • PHP 5.5+ 用于 v0.5.x 分支(当前稳定版)和 v1.x 分支(镜像当前稳定版)
  • PHP 7 用于 v2.0 分支(开发中)支持生成器委托和返回表达式
建议
安装

推荐使用 Composer 包管理器安装。有关安装和使用 Composer 的信息,请参阅 Composer 安装指南

运行以下命令在项目中使用此库

composer require icicleio/socket

您也可以手动编辑 composer.json 将此库添加为项目依赖项。

// composer.json
{
    "require": {
        "icicleio/socket": "^0.5"
    }
}

套接字组件实现基于协程的网络套接字,包括服务器和数据报。创建服务器和接受连接非常简单,只需几行代码。

以下示例实现了一个简单的 HTTP 服务器,监听 127.0.0.1:8080,并以客户端请求的内容作为响应体。此示例使用协程(请参阅 协程 API 文档)和此包提供的基本套接字。

use Icicle\Coroutine\Coroutine;
use Icicle\Loop;
use Icicle\Socket\Server\DefaultServerFactory;
use Icicle\Socket\Server\Server;
use Icicle\Socket\Socket;

$server = (new DefaultServerFactory())->create('localhost', 8080);

$generator = function (Server $server) {
    printf("Server listening on %s:%d\n", $server->getAddress(), $server->getPort());

    $generator = function (Socket $socket) {
        $request = '';
        do {
            $request .= (yield $socket->read(0, "\n"));
        } while (substr($request, -4) !== "\r\n\r\n");

        $message = sprintf("Received the following request:\r\n\r\n%s", $request);

        $data  = "HTTP/1.1 200 OK\r\n";
        $data .= "Content-Type: text/plain\r\n";
        $data .= sprintf("Content-Length: %d\r\n", strlen($message));
        $data .= "Connection: close\r\n";
        $data .= "\r\n";
        $data .= $message;

        yield $socket->write($data);

        $socket->close();
    };

    while ($server->isOpen()) {
        // Handle client in a separate coroutine so this coroutine is not blocked.
        $coroutine = new Coroutine($generator(yield $server->accept()));
        $coroutine->done(null, function ($exception) {
            printf("Client error: %s\n", $exception->getMessage());
        });
    }
};

$coroutine = new Coroutine($generator($server));
$coroutine->done();

Loop\run();

文档

函数原型

以下语法描述了对象实例方法的原型

ClassOrInterfaceName::methodName(ArgumentType $arg): ReturnType

服务器

Icicle\Socket\Server\BasicServer 类实现了 Icicle\Socket\Server\Server,这是一个用于创建 TCP 服务器和接受连接的基于协程的接口。

BasicServer 构造函数

$server = new BasicServer(resource $socket)

从一个由 stream_socket_server() 生成的流套接字服务器资源创建服务器。通常最好使用 Icicle\Socket\Server\DefaultServerFactory 来创建 Icicle\Socket\Server\BasicServer 实例。

accept()

Server::accept(): Generator

一个协程,当接受连接时,通过实现 Icicle\Socket\Socket 的对象解析。

getAddress()

Server::getAddress(): string

以字符串形式返回本地 IP 地址。

getPort()

Server::getPort(): int

返回本地端口。

ServerFactory

Icicle\Socket\Server\DefaultServerFactory(实现 Icicle\Socket\Server\ServerFactory)可用于从 IP 或 UNIX 套接字路径、端口号(UNIX 套接字为 null)和选项列表创建服务器实例。

create()

ServerFactory::create(
    string $host,
    int $port = null,
    mixed[] $options = []
): Server

创建一个绑定并监听给定 IP 或 UNIX 套接字路径和端口号(UNIX 套接字为 null)的服务器。

套接字

Icicle\Socket\NetworkSocket 对象实现了 Icicle\Socket\Socket,并用作由 Icicle\Socket\Server\BasicServer::accept() 返回的协程的完成值(请参阅上面的文档)。(注意,Icicle\Socket\Server\BasicServer 可以很容易地扩展和修改,以便使用实现 Icicle\Socket\Socket 的不同对象来满足接受请求。)

该类扩展了 Icicle\Stream\Pipe\DuplexPipe,因此继承了所有可读和可写流方法,并添加了以下方法。

NetworkSocket 构造函数

$socket = new NetworkSocket(resource $socket)

从给定的流套接字资源创建套接字对象。

enableCrypto()

Socket::enableCrypto(int $method, float $timeout = 0): \Generator

在套接字上启用加密。对于从 Icicle\Socket\Server\Server::accept() 创建的套接字对象,在创建服务器套接字时必须已提供 PEM 文件(请参阅 Icicle\Socket\Server\ServerFactory)。当在远程客户端(例如,由 Icicle\Socket\Server\Server::accept() 创建)上启用加密时,使用 STREAM_CRYPTO_METHOD_*_SERVER 常量,当在本地客户端连接(例如,由 Icicle\Socket\Connector\Connector::connect() 创建)上启用加密时,使用 STREAM_CRYPTO_METHOD_*_CLIENT 常量。

isCryptoEnabled()

Socket::isCryptoEnabled(): bool

确定是否在套接字上启用了加密。

unshift()

Socket::unshift(string $data): void

确定是否在套接字上启用了加密。

getLocalAddress()

Socket::getLocalAddress(): string

以字符串形式返回本地 IP 地址。

getLocalPort()

Socket::getLocalPort(): int

返回本地端口。

getRemoteAddress()

Socket::getRemoteAddress(): string

以字符串形式返回远程 IP 地址。

getRemotePort()

Socket::getRemotePort(): int

返回远程端口。

连接器

Icicle\Socket\Connector\DefaultConnector 类(实现了 Icicle\Socket\Connector\Connector 接口)异步连接到远程服务器,当连接成功建立时,返回一个协程,该协程被填充为 Icicle\Socket\Socket 实例。请注意,主机应以 IP 地址的形式给出,因为 PHP 执行的 DNS 查找是同步的(阻塞的)。如果您想使用域名而不是 IP 地址,请参阅 DNS 组件 中的 Icicle\Dns\Connector\Connector

connect()

Connector::connect(
    string $host,
    int|null $port,
    mixed[] $options = []
): \Generator

异步连接到给定 IP 地址或 Unix 套接字路径上的指定端口号(对于 Unix 套接字为 null)。

数据报

Icicle\Socket\Datagram\BasicDatagram 类实现了 Icicle\Socket\Datagram\Datagram,这是一个基于协程的接口,用于创建 UDP 监听器和发送器。

BasicDatagram 构造函数

$datagram = new BasicDatagram(resource $socket)

从由 stream_socket_server() 生成的流套接字服务器资源创建数据报。通常,使用 Icicle\Socket\Datagram\DefaultDatagramFactory 创建 Icicle\Socket\Datagram\BasicDatagram 实例会更好。

receive()

Datagram::receive(int $length, float $timeout): Generator

当在 UDP 套接字(数据报)上接收到数据时,这是一个协程,其结果为数组。该数组是一个包含 IP 地址、端口和接收到的数据的 0 索引数组,顺序为 IP 地址、端口和数据。

send()

Datagram::send(
    string $address,
    int $port,
    string $data
): \Generator

将给定的数据发送到指定的 IP 地址和端口号。一旦数据成功发送,该协程就会填充发送的数据量。

getAddress()

Datagram::getAddress(): string

以字符串形式返回本地 IP 地址。

getPort()

Datagram::getPort(): int

返回本地端口。

DatagramFactory

Icicle\Socket\Datagram\DefaultDatagramFactory(实现了 Icicle\Socket\Datagram\DatagramFactory 接口)可用于从主机名或 Unix 套接字路径、端口号(对于 Unix 套接字为 null)和选项列表创建数据报实例。

create()

DatagramFactory::create(
    string $host,
    int $port = null,
    mixed[] $options = []
): Datagram

创建一个绑定并监听给定 IP 地址和端口号的数据报。此实现中没有定义任何选项。

函数

Socket\connect()

Icicle\Socket\connect(
    string $ip,
    int|null $port,
    array $options = []
): \Generator

异步连接到给定主机上的指定端口。使用全局连接器接口,该接口可以使用 Icicle\Socket\connector() 设置。

Socket\connector()

Icicle\Socket\connector(
    Connector|null $connector = null
): Connector

获取全局连接器实例。如果提供了 Connector 实例,则该实例被设置为全局连接器实例。