PHP的fsockopen方式访问接口慢的缘由与优化方案

在开发过程当中经常遇到这样的需求,模拟浏览器访问某接口,并获取返回数据。咱们比较常使用的方法是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就压缩后再返回,浏览器获得内容后解压缩再显示。可是若是内容过短的话,压缩后体积反而会增长,再加上压缩、解压缩的时间,就更加得不偿失了。

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

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

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

相关文章
相关标签/搜索