php_http_parser是基于ode.jshttp-parser的PHP扩展,可用于实现纯异步PHP程序
libcurl提供了异步调用方式,有两种风格:
ONEMULTIHANDLEMANYEASYHANDLES:加入多个easyhadle后执行curl_multi_perform方法。该方法在phpcurl扩展中有对应实现。但最后一步curl_multi_perform是阻塞的。
MULTI_SOCKET,这个是真正的非阻塞方法,但需要自行实现evetloop,且封装较为困难,目前在php中没有对应实现。经过调研,curl_multi_socket_actio跟php内核结合困难度很高。
除此之外,基本上没有真正的实现异步http请求的php扩展。目前仅有部分纯php实现的版本,比如tsf中的httpcliet实现。使用纯php实现的问题主要受限于http解析的性能。因此考虑将这一模块用扩展的方式来实现。ode.jshttp-parser就是一个很好的c语言的http解析库。php_http_parser就是对其做的一个封装,在php中暴露出相应的接口。
为了实现真正的非阻塞请求,仍然需要自己实现evetloop。目前推荐结合swoole使用,以获得更好的性能。
使用方式$buffs = array("HTTP/1.1 301 Moved Permaetly\r\","Locatio: https://www.google.com/\r\","Cotet-Type: text/html; charset=UTF-8\r\","Date: Su, 26 Apr 2009 11:11:49 GMT\r\","Expires: Tue, 26 May 2009 11:11:49 GMT\r\","Cache-Cotrol: public, max-age=2592000\r\","Server: gws\r\","Cotet-Legth: 193\r\","\r\","<HTML><HEAD><meta http-equiv=\"cotet-type\" cotet=\"text/html;charset=utf-8\">\","<TITLE>301 Moved</TITLE></HEAD><BODY>\","<H1>301 Moved</H1>\","The documet has moved\","<A HREF=\"https://www.google.com/\">here</A>.\r\" ,"<A HREF=\"https://www.google.com/\">here</A>.\r\" ,"<A HREF=\"https://www.google.com/\">here</A>.\r\" ,"<A HREF=\"https://www.google.com/\">here</A>.\r\" ,"<A HREF=\"https://www.google.com/\">here</A>.\r\","</BODY></HTML>\r\");$hp = ew HttpParser();foreach($buffs as $buff){ $ret = $hp->execute($buff); if($ret !== false){ echo $ret; break; }}虽然http请求可能分包发送,HttpParser会将所有包合并在一起后,出发body事件,然后调用相应的回调方法。诸如header回调,目前暂未实现。另外,此处需要自行实现timeout逻辑。
示例代码是结合swoole_cliet与swPromise框架实现的一个异步httpcliet。籍此可以实现真正的非阻塞的PHP程序。
class HttpClietFuture implemets FutureItf { protected $url = ull; protected $post = ull; protected $proxy = false; public fuctio __costruct($url, $post = array(), $proxy = array()) { $this->url = $url; $this->post = $post; if($proxy){ $this->proxy = $proxy; } } public fuctio ru(Promise &$promise) { $cli = ew \swoole_cliet ( SWOOLE_TCP, SWOOLE_SOCK_ASYNC ); $urlIfo = parse_url ( $this->url ); if(!isset($urlIfo ['port']))$urlIfo ['port'] = 80; $httpParser = ew \HttpParser(); $cli->o ( "coect", fuctio ($cli)use($urlIfo){ $host = $urlIfo['host']; if($urlIfo['port'])$host .= ':'.$urlIfo['port']; $req = array(); $req[] = "GET {$this->url} HTTP/1.1\r\"; $req[] = "User-Aget: PHP swAsyc\r\"; $req[] = "Host:{$host}\r\"; $req[] = "Coectio:close\r\"; $req[] = "\r\"; $req = implode('', $req); $cli->sed ( $req ); } ); $cli->o ( "receive", fuctio ($cli, $data = "") use(&$httpParser, &$promise) { $ret = $httpParser->execute($data); if($ret !== false){ $cli->close(); $promise->accept(['http_data'=>$ret]); } } ); $cli->o ( "error", fuctio ($cli) use(&$promise) { $promise->reject (); } ); $cli->o ( "close", fuctio ($cli) { } ); if($this->proxy){ $cli->coect ( $this->proxy['host'], $this->proxy ['port'], 1 ); }else{ $cli->coect ( $urlIfo ['host'], $urlIfo ['port'], 1 ); } }}性能[web@gz-web01 php_http_parser]$ time /data/server/php/bi/php http_parser.php 2000000real 0m11.489suser 0m11.435ssys 0m0.017s1个worker进程
./http_load -fetches 20000 -parallel 100 9502.listasyc 20000 fetches, 100 max parallel, 2.02e+06 bytes, i 5.94536 secods101 mea bytes/coectio3363.97 fetches/sec, 339761 bytes/secmsecs/coect: 0.0473873 mea, 1.155 max, 0.019 mimsecs/first-respose: 29.6366 mea, 51.736 max, 15.22 miHTTP respose codes:code 200 -- 20000-bash: history: write error: Success2个worker进程
./http_load -fetches 20000 -parallel 100 9502.listasyc 20000 fetches, 100 max parallel, 2.02e+06 bytes, i 3.17119 secods101 mea bytes/coectio6306.77 fetches/sec, 636984 bytes/secmsecs/coect: 0.0643583 mea, 1.211 max, 0.023 mimsecs/first-respose: 15.7489 mea, 32.425 max, 3.242 miHTTP respose codes:code 200 -- 20000-bash: history: write error: Success4个woker进程
./http_load -fetches 20000 -parallel 100 9502.listasyc 20000 fetches, 100 max parallel, 2.02e+06 bytes, i 1.57194 secods101 mea bytes/coectio12723.2 fetches/sec, 1.28504e+06 bytes/secmsecs/coect: 0.0815263 mea, 1.349 max, 0.02 mimsecs/first-respose: 7.65904 mea, 22.568 max, 1.221 miHTTP respose codes:code 200 -- 20000-bash: history: write error: Success8个woker进程
./http_load -fetches 20000 -parallel 100 9502.listasyc 20000 fetches, 100 max parallel, 2.02e+06 bytes, i 1.02967 secods101 mea bytes/coectio19423.8 fetches/sec, 1.9618e+06 bytes/secmsecs/coect: 0.147502 mea, 1.575 max, 0.014 mimsecs/first-respose: 3.17218 mea, 22.566 max, 0.339 miHTTP respose codes:code 200 -- 20000-bash: history: write error: Success
评论