php中使用fsockopen实现异步请求
php执行一段程序,有可能几毫秒就执行完毕,也有可能耗时较长。例如,用户下单这个事件,如果调用了些第三方服务进行发邮件、短信、推送等通知,可能导致前端一直在等待。而有的时候,我们并不关心这些耗时脚本的返回结果,只要执行就行了。这时候就需要采用异步的方式执行。
众所周知,PHP没有直接支持多线程这种东西。我们可以采用折衷的方式实现。这里主要说的就是fsockopen。
通过fsockopen发送请求并忽略返回结果,程序可以马上返回。
示例代码:
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET /backend.php HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
/*忽略执行结果
while (!feof($fp)) {
echo fgets($fp, 128);
}*/
fclose($fp);
}
需要注意的是我们需要手动拼出header头信息。通过打开注释部分,可以查看请求返回结果,但这时候又变成同步的了,因为程序会等待返回结果才结束。
实际测试的时候发现,不忽略执行结果,调试的时候每次都会成功发送sock请求;但忽略执行结果,经常看到没有成功发送sock请求。查看nginx日志,发现很多状态码为499的请求。
后来找到了原因:fwrite之后马上执行fclose,nginx会直接返回499,不会把请求转发给php处理。
客户端主动端口请求连接时,NGINX 不会将该请求代理给上游服务(FastCGI PHP 进程),这个时候 access log 中会以 499 记录这个请求。
解决方案:
1)nginx.conf增加配置
# 忽略客户端中断
fastcgi_ignore_client_abort on;
2)fwrite之后使用usleep函数休眠20毫秒:
usleep(20000);
后来测试就没有发现失败的情况了。
附上完整代码:
<?php
/**
* 工具类
* */
class FsockService {
public static function post($url, $param){
$host = parse_url($url, PHP_URL_HOST);
$port = 80;
$errno = '';
$errstr = '';
$timeout = 30;
$data = http_build_query($param);
// create connect
$fp = fsockopen($host, $port, $errno, $errstr, $timeout);
if(!$fp){
return false;
}
// send request
$out = "POST ${url} HTTP/1.1\r\n";
$out .= "Host:${host}\r\n";
$out .= "Content-type:application/x-www-form-urlencoded\r\n";
$out .= "Content-length:".strlen($data)."\r\n";
$out .= "Connection:close\r\n\r\n";
$out .= "${data}";
fwrite($fp, $out);
//忽略执行结果;否则等待返回结果
// if(APP_DEBUG === true){
if(false){
$ret = '';
while (!feof($fp)) {
$ret .= fgets($fp, 128);
}
}
usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499
fclose($fp);
}
public static function get($url, $param){
$host = parse_url($url, PHP_URL_HOST);
$port = 80;
$errno = '';
$errstr = '';
$timeout = 30;
$url = $url.'?'.http_build_query($param);
// create connect
$fp = fsockopen($host, $port, $errno, $errstr, $timeout);
if(!$fp){
return false;
}
// send request
$out = "GET ${url} HTTP/1.1\r\n";
$out .= "Host:${host}\r\n";
$out .= "Connection:close\r\n\r\n";
fwrite($fp, $out);
//忽略执行结果;否则等待返回结果
// if(APP_DEBUG === true){
if(false){
$ret = '';
while (!feof($fp)) {
$ret .= fgets($fp, 128);
}
}
usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499
fclose($fp);
}
}
?>
参考:
1、PHP实现异步调用方法研究 | 风雪之隅
http://www.laruence.com/2008/04/14/318.html
2、PHP fsockopen 异步调用接口在nginx上偶尔实效的情况 - 张炜施 - 博客园
http://www.cnblogs.com/zhangweishi/p/5306813.html
3、php 利用fsockopen GET/POST 提交表单及上传文件 - 傲雪星枫 - 博客频道 - CSDN.NET
http://blog.csdn.net/fdipzone/article/details/11712607
4、关于PHP的异步调用 - 浮云比翼 - 博客园
http://www.cnblogs.com/fuyunbiyi/archive/2013/03/27/2985089.html
php中使用fsockopen实现异步请求的更多相关文章
- 微信小程序中使用Async-await方法异步请求变为同步请求
微信小程序中有些 Api 是异步的,无法直接进行同步处理.例如:wx.request.wx.showToast.wx.showLoading等.如果需要同步处理,可以使用如下方法: 注意: Async ...
- WeChat-SmallProgram:微信小程序中使用Async-await方法异步请求变为同步请求
微信小程序中有些 Api 是异步的,无法直接进行同步处理.例如:wx.request.wx.showToast.wx.showLoading 等.如果需要同步处理,可以使用如下方法: 提示:Async ...
- angular中处理多个异步请求的方法汇总
在实际业务中经常需要等待几个请求完成后再进行下一步操作.但angularjs中$http不支持同步的请求. 解决方法一: $http多层嵌套 $http.get('url1').success(fun ...
- vue中使用axios(异步请求)和mock.js 模拟虚假数据
一.使用axios 1.安装 npm install --save axios 2.引用 import Axios from 'axios' Vue.prototype.Axios = Axios 二 ...
- vue(6)—— vue中向后端异步请求
异步请求 其实什么是异步请求已经不用多说了,通俗的说,就是整个页面不会刷新,需要更新的部分数据做局部刷新,其他数据不变. 学到这里,你应该用过jquery里的ajax了,所以很能理解了,不多说了.详细 ...
- CAT中实现异步请求的调用链查看
CAT简介 CAT(Central Application Tracking),是美团点评基于 Java 开发的一套开源的分布式实时监控系统.美团点评基础架构部希望在基础存储.高性能通信.大规模在线访 ...
- 实现在Android简单封装类似JQuery异步请求
在android开发中经常会使用异步请求数据,通常会使用handler或者AsyncTask去做,handler 配合message 使用起来比较麻烦,AsyncTask 线程池只允许128个线程工作 ...
- Android简单封装类似JQuery异步请求
在android开发中经常会使用异步请求数据,通常会使用handler或者AsyncTask去做,handler 配合message 使用起来比较麻烦,AsyncTask 线程池只允许128个线程工作 ...
- MVC&WebForm对照学习:ajax异步请求
写在前面:由于工作需要,本人刚接触asp.net mvc,虽然webform的项目干过几个.但是也不是很精通.抛开asp.net webform和asp.net mvc的各自优劣和诸多差异先不说.我认 ...
随机推荐
- 前端css兼容性与易混淆的点
一.常用的骨灰级清除浮动 .clearfix:after { content: "."; display: block; height:; clear: both; visibil ...
- Fabio 安装和简单使用
Fabio(Go 语言):https://github.com/eBay/fabio Fabio 是一个快速.现代.zero-conf 负载均衡 HTTP(S) 路由器,用于部署 Consul 管理的 ...
- bootstrap + requireJS+ director+ knockout + web API = 一个时髦的单页程序
也许单页程序(Single Page Application)并不是什么时髦的玩意,像Gmail在很早之前就已经在使用这种模式.通常的说法是它通过避免页面刷新大大提高了网站的响应性,像操作桌面应用程序 ...
- 我为Net狂 ~ 社交平台系列小集合!
微信平台: 我为Net狂(dotNetCrazy) 资源贴吧: http://tieba.baidu.com/f?kw=毒逆天 个人博客: http://dunitian.cnblogs.com/ h ...
- 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送
微信支付之微信模板消息推送 今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...
- 关于.NET参数传递方式的思考
年关将近,整个人已经没有了工作和写作的激情,估计这个时候很多人跟我差不多,该相亲的相亲,该聚会喝酒的聚会喝酒,总之就是没有了干活的心思(我有很多想法,但就是叫不动我的手脚,所以我只能看着别人在做我想做 ...
- ObserverPattern(观察者模式)
import java.util.ArrayList; import java.util.List; /** * 观察者模式 * @author TMAC-J * 牵一发而动全身来形容观察者模式在合适 ...
- 【干货分享】流程DEMO-付款申请单
流程名: 付款申请单 业务描述: 包括每月固定开支.固定资产付款.办公用品付款.工资发放.个人所得税缴纳.营业税缴纳.公积金.社保缴纳和已签订合同的按期付款,最后是出纳付款,出纳核对发票. 流程发起 ...
- ReactiveCocoa代码实践之-UI组件的RAC信号操作
上一节是自己对网络层的一些重构,本节是自己一些代码小实践做出的一些demo程序,基本涵盖大多数UI控件操作. 一.用UISlider实现调色板 假设我们现在做一个demo,上面有一个View用来展示颜 ...
- MySQL:Fabric 安装
MySQL Fabric安装 MySQL Fabric是Oracle提供的用于辅助进行ha\sharding的工具,它的基本架构: 从上面看出,借助于Fabric, 可以搭建 HA 集群.Sharin ...