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的各自优劣和诸多差异先不说.我认 ...
随机推荐
- 微信小程序开发心得
微信小程序也已出来有一段时间了,最近写了几款微信小程序项目,今天来说说感受. 首先开发一款微信小程序,最主要的就是针对于公司来运营的,因为,在申请appid(微信小程序ID号)时候,需要填写相关的公司 ...
- 获取打开的Word文档
using Word = Microsoft.Office.Interop.Word; int _getApplicationErrorCount=0; bool _isMsOffice = true ...
- css3制作旋转动画
现在的css3真是强大,之前很多动画都是用jq来实现,但是css3制作的动画要比jq实现起来简单很多,今天呢,我自己也写了一个css旋转动画和大家分享.效果如下面的图片 思路:1.制作之前呢,我们先来 ...
- SAP CRM 显示消息/在消息中进行导航
向用户展示消息,在任何软件中都是十分重要的. 在SAP CRM WEB UI中展示消息,不是一项很难的任务,只需要创建消息并在之后调用方法来显示它 消息类和消息号: 我在SE91中创建了如下的消息类和 ...
- Android 调用百度地图API
一.到 百度地图开发平台下载SDK http://lbsyun.baidu.com/index.php?title=androidsdk/sdkandev-download 1.点击自定义下载 2.下 ...
- Tomcat 部署我的第一个程序
idea 生成war包.先双击clean,再双击package.生成成功之后就会产生war包. 第二步:将生成好的war文件复制到tomcat文件夹下. 第三步:配置tomcat的server.xml ...
- 1 selenium3.0.1无法打开火狐浏览器
[问题描述] 1.配置selenium3.0和java后,尝试打开火狐浏览器,提示缺少geckodriver驱动. [解决方案] 1.在http://www.seleniumhq.org/downlo ...
- <程序员从入门到精通> -- How
定位 自己才是职业生涯的管理者,想清楚自己的发展路径: 远期的理想是什么?近期的规划是什么?今日的任务和功课又是什么? 今日之任务或功课哪些有助于近期之规划的实现,而近期之规划是否有利于远期之理想? ...
- Hadoop
Hadoop应用场景 Hadoop是专为离线处理和大规模数据分析而设计的,它并不适合那种对几个记录随机读写的在线事务处理模式. 大数据存储:Hadoop最适合一次写入.多次读取的数据存储需求,如数据仓 ...
- .NET Core 1.0.1 升级汇总
ASP.NET Core BUG fix: ASP.NET Routing Port fix for "Request not matching route with defaults&qu ...