在开发过程中常常遇到这样的需求,模拟浏览器访问某接口,并获取返回数据。我们比较常使用的方法是fsockopen与接口建立连接,然后发出指令,然后通过fgets接受返回值。

但是我们发现,通过PHP模拟访问接口往往比浏览器访问同样的接口慢很多。这个问题困扰过我很久,今天终于找到原因了。我看网上很多朋友有同样的问题,分享出来供大家参考。

我们常常写这样的代码:

while(!feof($sHnd))
{
$line = fgets($sHnd,
4096);
}

fgets会获取文件描述符$sHnd的当前的4096(也可能是别的常数)个字节,如果还没有到4096个字节遇到换行符了,则只返回换行符及换行符之前的内容。

许多文档教程里也都是这么讲的,这段代码许多情况下也能正常执行。我一步一步跟踪PHP语句的耗时,发现前面若干次的fgets都很快,最耗时的是最后一次fgets,有时长达几秒,有时长达十几秒。

原来这是服务器的KeepAlive功能造成的,Apache有这么一个设置(nginx等其他web服务器也都有):KeepAlive,如果这个设置置为On,则完成一次请求后,服务器并不会关闭TCP连接,而是保持连接等待浏览器下次发起其他请求时直接利用这个连接。但是当fgets获取最后一段内容时没有发现换行符,也没有文件结束标志(feof()),所以fgets获取完内容后仍继续等待,希望遇到换行符或者其他内容以达到4096个字符。于是,就这样服务器和PHP耗上了,互相等待。耗了一会后,服务器先耗不起了,毕竟服务器的连接数很宝贵,当连接若干秒没有活动,就会关掉这个连接(Apache通过KeepAliveTimeout这个选项进行设置,这个值通常为5-15)。服务器关掉连接之后,PHP这边的fgets这才失落得返回最后一批内容,访问接口过程结束。

清楚了慢的原因就知道了解决方案了:

服务器返回的HTTP头中包含有内容长度这个属性,当已接受的内容长度与之相等时,我们就可以断定:接口内容已经获取完毕,不必再等了。具体做法是:每次获取不超过剩余总长度的内容(min(4096,
$leftlength))。剩余总长度为0时,跳出while(feof($xxxxx))的循环。

经过这样的修改,php通过sock方式访问接口速度慢的问题已经基本解决了,但还不够完美,继续速度优化的思路还在KeepAlive上。

大家都知道访问接口的耗时相当一部分是浪费在建立连接上,如果我们需要频繁调用接口的话,还有很大的优化余地。既然服务器保持了连接,那如果PHP也把连接保存下来那是不是就不用建立连接了?答案是肯定的:第一次访问接口时使用pfsockopen(pfsockopen与fsockopen唯一的区别就是它建立的是长连接)函数建立与服务器的连接,在访问完成后不关掉(fclose)连接,以后的访问就直接使用这个连接。具体到代码里就是:先判断有没有连接,如果有,继续用,如果没有,建立pfsockopen连接。

另外,如果接口返回内容比较短(比如:小于50字符)的话,还有优化的余地,那就是在HTTP请求头的Accept-Encoding中去掉gzip。它的作用是告诉服务器,我(浏览器)可以接受压缩过的内容,如果服务器也支持gzip就压缩后再返回,浏览器得到内容后解压缩再显示。但是如果内容太短的话,压缩后体积反而会增加,再加上压缩、解压缩的时间,就更加得不偿失了。

经过以上几步,访问接口速度应该与浏览器一样,理论上还会稍微快一点点。

http://blog.csdn.net/lzr77/article/details/9704405

http://blog.csdn.net/dazhi_100/article/details/46806519

PHP的fsockopen方式访问接口慢的原因与优化方案的更多相关文章

  1. 使用HttpURLConnection方式访问接口

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...

  2. 两种访问接口的方式(get和post)

    跨机器.跨语言的远程访问形式一共有三种:scoket发送数据包.http发送请求.rmi远程连接: http发送请求方式:分为post和get两种方式 importjava.io.IOExceptio ...

  3. 没有活动事务 链接服务器的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务

    在windows2003下执行分布式事务的时候出现如下情况. 一. 问题现象在执行分布式事务时,在sql server 2005下收到如下错误: 链接服务器"xxxxxxx"的 O ...

  4. Dojo Data Store——统一数据访问接口

    原文地址:http://www.infoq.com/cn/articles/wq-dojo-data-store 无论在传统的桌面应用还是在主流的互联网应用中,数据始终占据着软件应用中的核心地位.当下 ...

  5. SharePoint—用REST方式访问列表

    REST的定义与作用 在SharePoint 2010中,基本上有如下几种数据访问方式: 服务器端对象模型 LINQ to SharePoint Web Service 客户端对象模型 ADO.NET ...

  6. java servlet手机app访问接口(一)数据加密传输验证

    前面几篇关于servlet的随笔,算是拉通了 servlet的简单使用流程,接下去的文章将主要围绕手机APP访问接口这块出发续写,md5加密传输--->短信验证--->手机推送---> ...

  7. httpclient 认证方式访问http api/resutful api并获取json结果

    最近,因公司线上环境rabbitmq经常发生堆积严重的现象,于是跟运维组讨论,帮助开发个集中监控所有rabbitmq服务器运行情况的应用,需要通过java访问rabbitmq暴露的http api并接 ...

  8. 链接服务器"(null)"的 OLE DB 访问接口 "Microsoft.Jet.OLEDB.4.0" 返回了消息 "未指定的错误"。[手稿]

    消息 7302,级别 16,状态 1,第 1 行 无法创建链接服务器 "(null)" 的 OLE DB 访问接口 "Microsoft.JET.OLEDB.4.0&qu ...

  9. 21. 无法执行该操作,因为链接服务器”Server_202”的 OLE DB 访问接口 “SQLNCLI10″ 无法启动分布式事务”

    无法执行该操作,因为链接服务器”Server_202”的 OLE DB 访问接口 “SQLNCLI10″ 无法启动分布式事务” 原因:调用存储过程的方式有问题,必须用JDBC方式调用存储过程才可以正常 ...

随机推荐

  1. 获取获取docker的文件

    1.docke实例内mysql 导出文件 mysql -h yourhost -P yourport -u user -p dbname -e "select * from employee ...

  2. Wordpress Uncaught TypeError: b(...).not(...).filter(...).mediaelementplayer is not a function

    Wordpress 插件页面报错如下图: 原因及解决方法: 引入了两次 jquery.js 或 jquery.js 定义的变量导致报错,删除在插件页面自己引入的 jquery,js 即可解决报错. 大 ...

  3. CSU-1985 驱R符

    CSU-1985 驱R符 Description 阴阳师中有三中稀有度的式神R,SR,SSR,其中R的稀有度最低,每次抽符,会随机得到一种式神,然而子浩君对R式神已经深恶痛绝. 某天,子浩君突然发现, ...

  4. Flask-WebSocket案例

    实验1:实现初始的通信 客户端:用浏览器向服务端发送信息 服务端:首先接收浏览器发来的信息,并作出相应应答 第一步:需要导入模块: from flask import Flask,request fr ...

  5. 服务器(centos7)用nginx挂出多个网站的配置

    前提: 装好环境的centos7系统(其他版本也行),装好ngnix: 推荐:http://www.cnblogs.com/alsy/p/5296244.html 把你的项目上传到服务器上(可以用Xf ...

  6. 【转】unity自带寻路Navmesh入门教程(二)

    http://liweizhaolili.blog.163.com/blog/static/16230744201271210237616/ 上一节简单介绍了NavMesh寻路的基本用法,这次来介绍一 ...

  7. hihoCoder offer 收割练习赛 74B 取球游戏

    Observations 存在取球策略使得每个四连通块可以只剩一个球:保证取走一个球后仍然是个四连通块. 定义新的[相邻]关系:两球在同一行中且所在行中二者之间无其他球,或者两球在同一列且所在列中二者 ...

  8. BZOJ3531 [Sdoi2014]旅行 【树剖 + 线段树】

    题目 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰.为了方便,我们用 ...

  9. iOS 关于请求参数在cookie里面

    一.首先了解一下什么cookie cookie是在客户端存储服务器状态的一种机制.web服务器可以通过set-cookie或者set-cookie2 HTTP头部设置cookie. Cookie可以分 ...

  10. POJ 2635 The Embarrassed Cryptographer (千进制,素数筛,同余定理)

    The Embarrassed Cryptographer Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15767   A ...