首页 Order Swoole4 正文

Swoole4 [协程客户端] TCP/UDP客户端

金鹏头像 金鹏 Swoole4 2021-12-26 14:12:41 0 1173
导读:协程TCP/UDP客户端Coroutine\Client提供了TCP、UDP、unixSocket传输协议的Socket客户端封装代码,使用时仅需newSwool...

协程 TCP/UDP 客户端

Coroutine\Client 提供了 TCPUDPunixSocket 传输协议的 Socket 客户端封装代码,使用时仅需 new Swoole\Coroutine\Client 即可。

  • 实现原理

    • Coroutine\Client 的所有涉及网络请求的方法,Swoole 都会进行协程调度,业务层无需感知

    • 使用方法和 Client 同步模式方法完全一致

    • connect 超时设置同时作用于 ConnectRecvSend 超时

  • 继承关系

    • Coroutine\ClientClient 并不是继承关系,但 Client 提供的方法均可在 Coroutine\Client 中使用。请参考 Swoole\Client,在此不再赘述 。

    • Coroutine\Client 中可以使用 set 方法设置配置选项,使用方法和与 Client->set 完全一致,对于使用有区别的函数,在 set() 函数小节会单独说明

  • 使用示例

use Swoole\Coroutine\Client;
use function Swoole\Coroutine\run;

run(function () {
    $client = new Client(SWOOLE_SOCK_TCP);
    if (!$client->connect('127.0.0.1', 9501, 0.5))
    {
        echo "connect failed. Error: {$client->errCode}\n";
    }
    $client->send("hello world\n");
    echo $client->recv();
    $client->close();
});
  • 协议处理

协程客户端也支持长度和 EOF 协议处理,设置方法与 Swoole\Client 完全一致。

$client = new Swoole\Coroutine\Client(SWOOLE_SOCK_TCP);
$client->set(array(
    'open_length_check'     => true,
    'package_length_type'   => 'N',
    'package_length_offset' => 0, //第N个字节是包长度的值
    'package_body_offset'   => 4, //第几个字节开始计算长度
    'package_max_length'    => 2000000, //协议最大长度
));

connect()

连接到远程服务器。

Swoole\Coroutine\Client->connect(string $host, int $port, float $timeout = 0.5): bool
  • 参数

    • 功能:网络 IO 的超时时间;包括 connect/send/recv,超时发生时,连接会被自动 close,参考客户端超时规则

    • 值单位:秒【支持浮点型,如 1.5 表示 1s+500ms

    • 默认值0.5s

    • 其它值:无

    • 功能:远程服务器端口

    • 默认值:无

    • 其它值:无

    • 功能:远程服务器的地址【底层会自动进行协程切换解析域名为 IP 地址】

    • 默认值:无

    • 其它值:无

    • string $host

    • int $port

    • float $timeout

  • 提示

    • 如果连接失败,会返回 false

    • 超时后返回,检查 $cli->errCode110

  • 失败重试

connect 连接失败后,不可直接进行重连。必须使用 close 关闭已有 socket,然后再进行 connect 重试。

//连接失败
if ($cli->connect('127.0.0.1', 9501) == false) {
    //关闭已有socket
    $cli->close();
    //重试
    $cli->connect('127.0.0.1', 9501);
}
  • 示例

if ($cli->connect('127.0.0.1', 9501)) {
    $cli->send('data');
} else {
    echo 'connect failed.';
}

if ($cli->connect('/tmp/rpc.sock')) {
    $cli->send('data');
} else {
    echo 'connect failed.';
}

isConnected()

返回 Client 的连接状态

Swoole\Coroutine\Client->isConnected(): bool
  • 返回值

    isConnected 方法返回的是应用层状态,只表示 Client 执行了 connect 并成功连接到了 Server,并且没有执行 close 关闭连接。Client 可以执行 sendrecvclose 等操作,但不能再次执行 connect
    这不代表连接一定是可用的,当执行 sendrecv 时仍然有可能返回错误,因为应用层无法获得底层 TCP 连接的状态,执行 sendrecv 时应用层与内核发生交互,才能得到真实的连接可用状态。

    • 返回 false,表示当前未连接到服务器

    • 返回 true,表示当前已连接到服务器

send()

发送数据。

Swoole\Coroutine\Client->send(string $data): int|bool
  • 参数

    • 功能:为发送的数据,必须为字符串类型,支持二进制数据

    • 默认值:无

    • 其它值:无

    • string $data

  • 发送成功返回写入 Socket 缓存区的字节数,底层会尽可能地将所有数据发出。如果返回的字节数与传入的 $data 长度不同,可能是 Socket 已被对端关闭,再下一次调用 sendrecv 时将返回对应的错误码。

  • 发送失败返回 false,可以使用 $client->errCode 获取错误原因。

recv()

recv 方法用于从服务器端接收数据。

Swoole\Coroutine\Client->recv(float $timeout = 0): string|bool
  • 参数

    设置超时,优先使用指定的参数,其次使用 set 方法中传入的 timeout 配置。发生超时的错误码为 ETIMEDOUT

    • 功能:设置超时时间

    • 值单位:秒【支持浮点型,如 1.5 表示 1s+500ms

    • 默认值:参考客户端超时规则

    • 其它值:无

    • float $timeout

  • 返回值

    • 设置了通信协议recv 会返回完整的数据,长度受限于 package_max_length

    • 未设置通信协议,recv 最大返回 64K 数据

    • 未设置通信协议返回原始的数据,需要 PHP 代码中自行实现网络协议的处理

    • recv 返回空字符串表示服务端主动关闭连接,需要 close

    • recv 失败,返回 false,检测 $client->errCode 获取错误原因,处理方式可参考下文的完整示例

close()

关闭连接。

close 不存在阻塞,会立即返回。关闭操作没有协程切换。

Swoole\Coroutine\Client->close(): bool

peek()

窥视数据。

peek 方法直接操作 socket,因此不会引起协程调度

Swoole\Coroutine\Client->peek(int $length = 65535): string
  • 提示

    • peek 方法仅用于窥视内核 socket 缓存区中的数据,不进行偏移。使用 peek 之后,再调用 recv 仍然可以读取到这部分数据

    • peek 方法是非阻塞的,它会立即返回。当 socket 缓存区中有数据时,会返回数据内容。缓存区为空时返回 false,并设置 $client->errCode

    • 连接已被关闭 peek 会返回空字符串

set()

设置客户端参数。

Swoole\Coroutine\Client->set(array $settings): bool
  • 配置参数

  • Swoole\Client 的差异

    协程客户端提供了更细粒度的超时控制。可以设置:

    • timeout:总超时,包括连接、发送、接收所有超时

    • connect_timeout:连接超时

    • read_timeout:接收超时

    • write_timeout:发送超时

    • 参考客户端超时规则

  • 示例

use Swoole\Coroutine\Client;
use function Swoole\Coroutine\run;

run(function () {
    $client = new Client(SWOOLE_SOCK_TCP);
    $client->set(array(
        'timeout' => 0.5,
        'connect_timeout' => 1.0,
        'write_timeout' => 10.0,
        'read_timeout' => 0.5,
    ));

    if (!$client->connect('127.0.0.1', 9501, 0.5))
    {
        echo "connect failed. Error: {$client->errCode}\n";
    }
    $client->send("hello world\n");
    echo $client->recv();
    $client->close();
});

完整示例

use Swoole\Coroutine\Client;
use function Swoole\Coroutine\run;

run(function () {
    $client = new Client(SWOOLE_SOCK_TCP);
    if (!$client->connect('127.0.0.1', 9501, 0.5)) {
        echo "connect failed. Error: {$client->errCode}\n";
    }
    $client->send("hello world\n");
    while (true) {
        $data = $client->recv();
        if (strlen($data) > 0) {
            echo $data;
            $client->send(time() . PHP_EOL);
        } else {
            if ($data === '') {
                // 全等于空 直接关闭连接
                $client->close();
                break;
            } else {
                if ($data === false) {
                    // 可以自行根据业务逻辑和错误码进行处理,例如:
                    // 如果超时时则不关闭连接,其他情况直接关闭连接
                    if ($client->errCode !== SOCKET_ETIMEDOUT) {
                        $client->close();
                        break;
                    }
                } else {
                    $client->close();
                    break;
                }
            }
        }
        \Co::sleep(1);
    }
});
本文地址:https://www.jinpeng.work/?id=82
若非特殊说明,文章均属本站原创,转载请注明原链接。
广告3

欢迎 发表评论:

  • 请填写验证码

日历

«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930

控制面板

您好,欢迎到访网站!
  查看权限
广告2

退出请按Esc键