- 浏览: 610399 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
kangh:
转载的也拿出来 都不试一下 完全错误
Nginx+ffmpeg的HLS开源服务器搭建配置及开发详解 -
wangtxlz:
#cd builders/cmake#cmake .系统提示命 ...
crtmpserver流媒体服务器的介绍与搭建 -
hnraysir:
支持支持支持
手机Android音视频采集与直播推送,实现单兵、移动监控类应用 -
wuent:
把web服务器和php框架绑定到一起?真不建议这样。。。
Swoole(PHP高级Web开发框架) -
wuent:
有更详细的性能比较吗?php,python,java
PHP中的(伪)多线程与多进程
最近研究php多线程的问题,发现中文资源少的可怜,仅有的几篇文章被转了又转,但文中内容价值有限。搜索过程中发现国外很多网站引用的一篇文章写的不错,所以翻译过来。
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
http://blog.iyi.cn/start/
问题:
有没有办法在php中实现多线程呢?
假设你正在写一个基于多台服务器的php应用,理想的情况时同时向多台服务器发送请求,而不是一台接一台。
可以实现吗?
回答:
当有人想要实现并发功能时,他们通常会想到用fork或者spawn threads,但是当他们发现php不支持多线程的时候,大概会转换思路去用一些不够好的语言,比如perl。
其实的是大多数情况下,你大可不必使用fork或者线程,并且你会得到比用fork或thread更好的性能。
假设你要建立一个服务来检查正在运行的n台服务器,以确定他们还在正常运转。你可能会写下面这样的代码:
<?php $hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com"); $timeout = 15; $status = array(); foreach ($hosts as $host) { $errno = 0; $errstr = ""; $s = fsockopen($host, 80, $errno, $errstr, $timeout); if ($s) { $status[$host] = "Connectedn"; fwrite($s, "HEAD / HTTP/1.0rnHost: $hostrnrn"); do { $data = fread($s, 8192); if (strlen($data) == 0) { break; } $status[$host] .= $data; } while (true); fclose($s); } else { $status[$host] = "Connection failed: $errno $errstrn"; } } print_r($status); ?>
它运行的很好,但是在fsockopen()分析完hostname并且建立一个成功的连接(或者延时$timeout秒)之前,扩充这段代码来管理大量服务器将耗费很长时间。
因此我们必须放弃这段代码;我们可以建立异步连接-不需要等待fsockopen返回连接状态。PHP仍然需要解析hostname(所以直接使用ip更加明智),不过将在打开一个连接之后立刻返回,继而我们就可以连接下一台服务器。
有两种方法可以实现;PHP5中可以使用新增的stream_socket_client()函数直接替换掉fsocketopen()。PHP5之前的版本,你需要自己动手,用sockets扩展解决问题。
下面是PHP5中的解决方法:
<?php $hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com"); $timeout = 15; $status = array(); $sockets = array(); foreach ($hosts as $id => $host) { $s = stream_socket_client("$host:80", $errno, $errstr, $timeout,STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); if ($s) { $sockets[$id] = $s; $status[$id] = "in progress"; } else { $status[$id] = "failed, $errno $errstr"; } } while (count($sockets)) { $read = $write = $sockets; $n = stream_select($read, $write, $e = null, $timeout); if ($n > 0) { foreach ($read as $r) { $id = array_search($r, $sockets); $data = fread($r, 8192); if (strlen($data) == 0) { if ($status[$id] == "in progress") { $status[$id] = "failed to connect"; } fclose($r); unset($sockets[$id]); } else { $status[$id] .= $data; } } foreach ($write as $w) { $id = array_search($w, $sockets); fwrite($w, "HEAD / HTTP/1.0rnHost: " . $hosts[$id] . "rnrn"); $status[$id] = "waiting for response"; } } else { foreach ($sockets as $id => $s) { $status[$id] = "timed out " . $status[$id]; } break; } } foreach ($hosts as $id => $host) { echo "Host: $hostn"; echo "Status: " . $status[$id] . "nn"; } ?>
我们用stream_select()等待sockets打开的连接事件。stream_select()调用系统的select(2)函数来工作:前面三个参数是你要使用的streams的数组;你可以对其读取,写入和获取异常(分别针对三个参数)。stream_select()可以通过设置$timeout(秒)参数来等待事件发生-事件发生时,相应的sockets数据将写入你传入的参数。
下面是PHP4.1.0之后版本的实现,如果你已经在编译PHP时包含了sockets(ext/sockets)支持,你可以使用根上面类似的代码,只是需要将上面的streams/filesystem函数的功能用ext/sockets函数实现。主要的不同在于我们用下面的函数代替 stream_socket_client()来建立连接:
<?php // This value is correct for Linux, other systems have other values define('EINPROGRESS', 115); function non_blocking_connect($host, $port, &$errno, &$errstr, $timeout) { $ip = gethostbyname($host); $s = socket_create(AF_INET, SOCK_STREAM, 0); if (socket_set_nonblock($s)) { $r = @socket_connect($s, $ip, $port); if ($r || socket_last_error() == EINPROGRESS) { $errno = EINPROGRESS; return $s; } } $errno = socket_last_error($s); $errstr = socket_strerror($errno); socket_close($s); return false; } ?>
现在用socket_select()替换掉stream_select(),用socket_read()替换掉fread(),用 socket_write()替换掉fwrite(),用socket_close()替换掉fclose()就可以执行脚本了!
PHP5的先进之处在于,你可以用stream_select()处理几乎所有的stream-例如你可以通过include STDIN用它接收键盘输入并保存进数组,你还可以接收通过proc_open()打开的管道中的数据。
如果你想让PHP4.3.x自身拥有处理streams的功能,我已经为你准备了一个让fsockopen可以异步工作的patch。不赞成使用该补丁,该补丁不会出现在官方发布的PHP版本中,我在补丁中附带了stream_socket_client()函数的实现,通过它,你可以让你的脚本兼容 PHP5。
发表评论
-
nginx、php-fpm默认配置与性能–TCP socket还是unix domain socket
2015-04-02 11:14 1474前几天看到一篇博客,提到php所在服务器在大并发情况下,频 ... -
使用socket方式连接Nginx优化php-fpm性能
2015-04-01 13:49 0Nginx连接fastcgi的方式有 ... -
PHP中include和require的区别详解
2015-04-01 08:32 01、概要 require()语句的性能与includ ... -
PHP 中cookie 和 session 的分析
2015-03-31 12:33 0HP 中cookie 和session 的分析 ... -
php 经典的算法题你懂的
2015-03-31 12:31 0有5个人偷了一堆苹果,准备在第二天分赃。晚上,有一人遛出来, ... -
PHP最常用的2种设计模式工厂模式和单例模式介绍
2015-03-31 12:26 0简单来说,PHP单例模式就是一个功能用一个类来实现,并且在整 ... -
PHP 数据类型
2015-03-31 12:23 0PHP 数据类型 PHP 支持八种原始类型(type)。 ... -
PHP mcrypt启用、加密以及解密过程详解
2015-03-30 11:32 1463Mcrypt扩展库可以实现加密解密功能,就是既能将明文加密, ... -
PHP扩展实现类扩展
2015-03-27 14:08 580在第一篇文章中,我们所开发的扩展是单个函数,本篇文章看一下 ... -
PHP高级工程师的面试题
2015-03-06 10:35 01. 基本知识点 HTTP协议中几个状态码的含义:1x ... -
PHP面试中常见的面试试题与算法例子
2015-03-05 14:14 0下面是四道比较常见的题目,主要考察的是对字符串函数以及文件操 ... -
PHP实现四种常用的排序算法
2015-03-05 14:09 0插入排序(Insertion Sort),选择排序(Sele ... -
用swagger-php/ui做API测试
2015-02-13 09:46 3652功能: 1 swagger-php根据自定义的规则生成API ... -
app后端设计(0)--总目录
2015-01-23 18:03 0做了3年app相关的系统架构,api设计,先后在3个创业公司中 ... -
PHP中eAccelerator、memcached、xcache、APC 4个加速、缓存扩展的区别
2015-01-23 10:26 919这篇文章主要介绍了PHP ... -
PHP内核探索:zend_parse_parameters函数
2015-01-16 14:14 969最简单的获取函数调用者传递过来的参数便是使用zend_pars ... -
实战:用C写php扩展(二)
2015-01-16 11:05 1001一、前言 在我的上一篇文章“实战:用C写php扩展(一)”里介 ... -
实战:用C写php扩展(一)
2015-01-16 11:04 10201、 前言 首先,确保你的机器安装了apache和php。假 ... -
JavaScript or PHP 来检测移动设备
2014-09-22 10:04 635iPhone & iPod Detection T ... -
YII Framework学习教程-YII的Modules(模块化)
2014-08-27 11:04 757一个相对来说大的项目。如果按照yii生成的 ...
相关推荐
在PHP中实现多线程可能并不像其他支持多线程的语言那样直接,但可以通过一些技巧来模拟并发处理,比如使用`fsockopen`或`stream_socket_client`进行异步连接。`fsockopen`是一个PHP内置函数,用于创建一个到远程主机...
下载此文件,解压并上传到网站源码根目录。然后访问这个文件【例如您网站的源码是直接放在abc.com的根目录,则访问http://abc.com/pfsockopen.php】,直接点【开始执行替换操作】,即可。
二、如何解决fsockopen函数被禁用1、如果服务器没有同时禁用pfsockopen,那么直接将fsockopen函数替换为pfsockopen。具体操作:搜索程序中的字符串 fsockopen( 替换为 pfsockopen( 。示例如下修改前:$fp = ...
传统的PHP网络编程中,fsockopen函数通常用于创建一个TCP连接,并与远程服务器交互。然而,当面对需要同时向多台服务器发送请求的场景时,fsockopen由于其同步阻塞的性质,导致效率低下,无法满足高并发的需求。本文...
在PHP编程中,`fsockopen` 和 `pfsockopen` 是两个用于创建网络套接字连接的内置函数。它们允许开发者直接与服务器进行通信,比如执行HTTP请求、发送邮件等。然而,由于这些函数可能存在一定的安全隐患,比如可能被...
目前记得服务器PHP环境不能禁止fsockopen函数,否则邮件发送不了,但这问题也有解决的办法。总之,一开始使用,总有不顺,由于时间久远,现在想来,也不知道具体改了什么。所以,将现在正在使用的PHPMailer目录文件...
本篇文章将详细阐述如何在Windows和Linux环境下解决服务器不支持`curl_exec`的问题。 ### Windows环境下开启curl支持 1. **复制必需的动态链接库(DLL)文件**:首先,你需要从PHP安装目录中复制`libeay32.dll`, `...
解决办法有两种:一是使用问题二中的方法阻止织梦尝试从远程获取列表;二是如果可能,尝试在服务器上重新启用`fsockopen()`函数。 最后,问题四是另一种可能导致空白的情况,即服务器环境设置的问题。除了`...
要解决使用PHPMailer在服务器上不能正常发送邮件的问题,可以通过修改PHPMailer的class.smtp.php文件来实现。具体来说,需要更改连接到邮件服务器的代码段,从使用fsockopen函数改为stream_socket_client函数。这种...
解决办法包括使用加密技术、混淆代码或者利用免杀技术。 - **防火墙拦截**:防火墙可能会阻止payload与远程服务器之间的通信。可以通过更改使用的端口或使用代理服务器等方式绕过防火墙。 - **特定端口通道**:某些...