博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
swoole_event_add实现异步
阅读量:6256 次
发布时间:2019-06-22

本文共 6968 字,大约阅读时间需要 23 分钟。

swoole提供了swoole_event_add函数,可以实现异步。此函数可以用在Server或Client模式下。

swoole_event_add属于AsyncIO,必须运行在CLI 模式。

异步tcp客户端

stream_socket_client实现tcp同步客户端

示例:

上述代码是同步执行的。如何变成异步呢?

stream_socket_client实现tcp异步客户端

由于fread读取响应数据是同步堵塞的,我们将$fp加入到事件监听后,底层会自动将该socket设置为非阻塞模式。修改fread那一行:

swoole_event_add($fp, function($fp) {    echo $resp = fread($fp, 8192);    swoole_event_del($fp);//socket处理完成后,从epoll事件中移除socket    fclose($fp);});echo "Finish\n";  //swoole_event_add不会阻塞进程,这行代码会顺序执行

执行后输出:

Finishuse time:0.087 sHTTP/1.1 200 OKServer: AliyunOSSDate: Sat, 21 Apr 2018 08:36:40 GMTContent-Type: application/jsonContent-Length: 26Connection: keep-alivex-oss-request-id: 5ADAF81884D23C965A5D2614Accept-Ranges: bytesETag: "3B3B50D9C802324BB72A74FCD9060004"Last-Modified: Sat, 21 Apr 2018 04:43:33 GMTx-oss-object-type: Normalx-oss-hash-crc64ecma: 9917578698767912878x-oss-storage-class: StandardContent-MD5: OztQ2cgCMku3KnT82QYABA==x-oss-server-time: 5{"url":"http://52fhy.com"}

swoole_event_add函数原型

bool swoole_event_add(mixed $sock, mixed $read_callback, mixed $write_callback = null,    int $flags = null);

$sock可以为以下四种类型:

  • int,就是文件描述符,包括swoole_client->$sockswoole_process->$pipe或者其他fd
  • stream资源,就是stream_socket_client/fsockopen创建的资源
  • sockets资源,就是sockets扩展中socket_create创建的资源,需要在编译时加入 ./configure --enable-sockets
  • object,swoole_process或swoole_client,底层自动转换为管道或客户端连接的socket

多个tcp客户端实时交互

上面的例子,已经实现了异步tcp客户端。接下来的例子会复杂些:可以在客户端A输入,客户端B能实时收到,反之也可以。

首先,我们得创建个tcp_server:

swoole_tcp_server.php

on('Start', function(){ echo "Tcp server start. Waiting client... \n";});$serv->on('Connect', function($serv, $fd){ echo "New client fd:{$fd}. \n";});$serv->on('Receive', function($serv, $fd, $from_id, $data){ echo "Recv msg from fd:{$fd}:{$data}\n"; foreach ($serv->connections as $client) { if($fd != $client){ $serv->send($client, $data); } }});$serv->on('Close', function($serv, $fd){ echo "Client fd:{$fd} closed. \n";});$serv->start();

然后实现客户端:

event_add_tcp_client.php

先运行服务端:

$ php swoole_tcp_server.phpTcp server start. Waiting client...

打开两个终端,运行客户端:

$ php event_add_tcp_client.phpENTER MSG:

效果图:

swoole_client

其实swoole已经提供了异步的swoole_client,无需使用stream_socket_*系列函数:

on("connect", function(swoole_client $cli) { });$client->on("receive", function(swoole_client $cli, $data){ echo "Receive: $data"; $cli->send(str_repeat('A', 100)."\n"); sleep(1);});$client->on("error", function(swoole_client $cli){ echo "error\n";});$client->on("close", function(swoole_client $cli){ echo "Connection close\n";});$client->connect('127.0.0.1', 9001);

还有swoole实现的tcp/udp同步阻塞客户端:

$client = new swoole_client(SWOOLE_SOCK_TCP);if (!$client->connect('127.0.0.1', 9001, -1)){    exit("connect failed. Error: {$client->errCode}\n");}$client->send("hello world\n");echo $client->recv();$client->close();

swoole_client 函数原型:

swoole_client->__construct(int $sock_type, int $is_sync = SWOOLE_SOCK_SYNC, string $key);

可以使用swoole提供的宏来之指定类型,请参考 swoole常量定义

  • $sock_type表示socket的类型,如TCP/UDP
  • 使用$sock_type | SWOOLE_SSL可以启用SSL加密
    $is_sync表示同步阻塞还是异步非阻塞,默认为同步阻塞
  • $key用于长连接的Key,默认使用IP:PORT作为key。相同key的连接会被复用

php-fpm/apache环境下只能使用同步客户端。异步客户端只能使用在cli命令行环境。

异步http客户端

curl或者file_get_contents发送http请求是同步阻塞的。基于swoole_event_add封装可以实现异步。

swoole_event_add实现异步http客户端

event_add_http_client.php

http($url, $method, $postfields, $headers); $worker->write($response); }, true); $process->start(); //异步读取 swoole_event_add($process->pipe, function($pipe) use ($process){ $response = $process->read(); // print_r($response); if(is_callable($this->callback)){ call_user_func($this->callback, $response); //回调 } swoole_event_del($pipe); }); } public function setCallback($callback){ $this->callback = $callback; } /** * http请求 */ private function http($url, $method, $postfields = NULL, $headers = array()) { try{ $ssl = stripos($url,'https://') === 0 ? true : false; $ci = curl_init(); /* Curl settings */ curl_setopt($ci, CURLOPT_USERAGENT, @$_SERVER['HTTP_USER_AGENT']); //在HTTP请求中包含一个"User-Agent: "头的字符串。 curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 30); curl_setopt($ci, CURLOPT_TIMEOUT, 30); curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ci, CURLOPT_ENCODING, ""); if ($ssl) { curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查 curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, 2); // 从证书中检查SSL加密算法是否存在 } curl_setopt($ci, CURLOPT_HEADER, FALSE); switch ($method) { case 'POST': curl_setopt($ci, CURLOPT_POST, TRUE); if (!empty($postfields)) { curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); } break; } curl_setopt($ci, CURLOPT_URL, $url ); curl_setopt($ci, CURLOPT_HTTPHEADER, $headers ); curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE ); $response = curl_exec($ci); $httpCode = curl_getinfo($ci, CURLINFO_HTTP_CODE); $httpInfo = curl_getinfo($ci); if (FALSE === $response) throw new Exception(curl_error($ci), curl_errno($ci)); } catch(Exception $e) { throw $e; } //echo '
';        //var_dump($response);        //var_dump($httpInfo);        curl_close ($ci);        return $response;    }}$client = new HttpClient('http://www.52fhy.com/test.json');$client->setCallback(function($response){    print_r($response);});echo "OK\n";

运行:

$ php event_add_http_client.phpOK{"url":"http://52fhy.com"}[

由返回结果可以看出,客户端请求是异步执行的。

swoole_http_client

Swoole也内置了http异步客户端(swoole>=1.8.0)。

相比curl和file_get_contents这样PHP提供的Http客户端,swoole_http_client最大的优势是支持大量并发。

file_get_contents只能同时请求一个URL,并发只能通过开启多进程实现。curl提供了curl_multi功能实现并发基于select和多线程。并发能力都很差。而swoole_http_client是基于epoll实现的异步客户端,没有并发限制,可在一个进程内同时并发上万请求。更多介绍详见。

示例:

get:

$cli = new swoole_http_client('www.52fhy.com', 80);$cli->setHeaders(['User-Agent' => "swoole"]);$cli->get('/test.json', function ($cli) {    echo $cli->body;});echo "ok\n";

输出:

ok{"url":"http://52fhy.com"}

post:

$cli = new swoole_http_client('127.0.0.1', 81); $cli->post('/post_demo.php', array("a" => '1234', 'b' => '456'), function ($cli) {    echo "Length: " . strlen($cli->body) . "\n";    echo $cli->body;});echo "ok\n";

websocket:

on('message', function ($_cli, $frame) { // var_dump($frame); echo $frame->data;});$cli->upgrade('/', function ($cli) { $cli->push("hello world");});echo "ok\n";

发送完客户端会立即close。

参考

1、swoole_event_add

2、Client
3、利用swoole_process和eventloop实现php异步编程
4、关于swoole_process的一些使用疑惑
5、swoole多进程操作
6、swoole教程第一节:进程管理模块(Process)-中(消息队列)
7、PHP编程中尝试程序并发的几种方式总结
8、1.8.0 使用内置Http异步客户端
9、异步Http/WebSocket客户端

转载地址:http://yoxsa.baihongyu.com/

你可能感兴趣的文章
android 打包
查看>>
FUCKED-BUG之临时对象的生死
查看>>
一句话开启XP_CMDSHELL
查看>>
【100题】第四十五题 雅虎面试两道题(矩阵判断、数组划分)
查看>>
MySQL基础知识
查看>>
HTML页面优化
查看>>
centos6下安装docker
查看>>
常见的算法PHP 版,自整理
查看>>
使用UITableView隐藏的复选功能
查看>>
自定义下拉菜单(按钮下面出现下拉菜单),失去焦点后,如何下拉菜单自动消失,以及弹出窗体位置一直变化问题...
查看>>
uboot指令和环境变量
查看>>
Python之模块(二)
查看>>
Python跳出循环语句continue与break的区别
查看>>
内存中堆,栈的区别
查看>>
JavaScript
查看>>
django 配置邮件发送 send_email
查看>>
程序员聊人生
查看>>
ScrollView中嵌套WebView SrcollView自动向下滚动
查看>>
Python尾递归-创始人为何不愿TRE以及我们如何模拟TRE
查看>>
PKUSC2016
查看>>