当前位置: 首页 > 文档资料 > Swoole 中文文档 >

协程TCP/UDP客户端

优质
小牛编辑
146浏览
2023-12-01

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()函数小节会单独说明
  • 使用示例

    Co\run(function(){
      $client = new Swoole\Coroutine\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'     => 1,
        '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
  • 参数

    • string $host

      • 功能:远程服务器的地址【底层会自动进行协程切换解析域名为IP地址】
      • 默认值:无
      • 其它值:无
    • int $port

      • 功能:远程服务器端口
      • 默认值:无
      • 其它值:无
    • float $timeout

      • 功能:网络IO的超时时间;包括connect/send/recv,超时发生时,连接会被自动close , 参考客户端超时规则
      • 值单位: 秒【支持浮点型,如1.5表示1s+500ms
      • 默认值0.5s
      • 其它值:无
  • 提示

    • 如果连接失败,会返回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.";
      }

send()

发送数据。

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

    • string $data

      • 功能:为发送的数据,必须为字符串类型,支持二进制数据
      • 默认值:无
      • 其它值:无
  • 发送成功返回写入Socket缓存区的字节数,底层会尽可能地将所有数据发出。如果返回的字节数与传入的$data长度不同,可能是Socket已被对端关闭,再下一次调用sendrecv时将返回对应的错误码。

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

recv()

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

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

    • float $timeout
      • 功能:设置超时时间
      • 值单位: 秒【支持浮点型,如1.5表示1s+500ms
      • 默认值-1
      • 其它值:无
  • 返回值

    • 设置了通信协议recv会返回完整的数据,长度受限于package_max_length
    • 未设置通信协议,recv最大返回64K数据
    • 未设置通信协议返回原始的数据,需要PHP代码中自行实现网络协议的处理
    • recv返回空字符串表示服务端主动关闭连接,需要close
    • recv失败,返回false,检测$client->errCode获取错误原因
  • 超时设置

    • 传入了$timeout,优先使用指定的timeout参数, 参考客户端超时规则
    • 未传入$timeout,但在connect时指定了超时时间,自动以connect超时时间作为recv超时时间
    • 未传入$timeout,未设置connect超时,将设置为-1表示永不超时
    • 发生超时的错误码为ETIMEDOUT

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): string
  • 配置参数

  • Swoole\Client的差异

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

    • timeout:总超时,包括连接、发送、接收所有超时
    • connect_timeout:连接超时
    • read_timeout:接收超时
    • write_timeout:发送超时
    • 参考客户端超时规则
  • 示例

Co\run(function(){
    $client = new Swoole\Coroutine\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();
});