php多线程实现管道通信,代码如下:
<?php /* 管道通信: 1. 管道可以认为是一个队列,不同的线程都可以往里面写东西,也都可以从里面读东西。写就是 在队列末尾添加,读就是在队头删除。 2. 管道一般有大小,默认一般是4K,也就是内容超过4K了,你就只能读,不能往里面写了。 3. 默认情况下,管道写入以后,就会被阻止,直到读取他的程序读取把数据读完。而读取线程也会被阻止, 直到有进程向管道写入数据。当然,你可以改变这样的默认属性,用stream_set_block 函数,设置成非阻断模式。 一个封装好的管道类。 */ class Pipe { public $fifoPath; private $w_pipe; private $r_pipe; /** * 自动创建一个管道 * * @param string $name 管道名字 * @param int $mode 管道的权限,默认任何用户组可以读写 */ function __construct($name = 'pipe', $mode = 0666) { $fifoPath = "/tmp/$name." . posix_getpid(); if (!file_exists($fifoPath)) { if (!posix_mkfifo($fifoPath, $mode)) { error("create new pipe ($name) error."); return false; } } else { error( "pipe ($name) has exit."); return false; } $this->fifoPath = $fifoPath; } // 写管道函数开始 function open_write() { $this->w_pipe = fopen($this->fifoPath, 'w'); if ($this->w_pipe == NULL) { error("open pipe {$this->fifoPath} for write error."); return false; } return true; } function write($data) { return fwrite($this->w_pipe, $data); } function write_all($data) { $w_pipe = fopen($this->fifoPath, 'w'); fwrite($w_pipe, $data); fclose($w_pipe); } function close_write() { return fclose($this->w_pipe); } /// 读管道相关函数开始 function open_read() { $this->r_pipe = fopen($this->fifoPath, 'r'); if ($this->r_pipe == NULL) { error("open pipe {$this->fifoPath} for read error."); return false; } return true; } function read($byte = 1024) { return fread($this->r_pipe, $byte); } function read_all() { $r_pipe = fopen($this->fifoPath, 'r'); $data = ''; while (!feof($r_pipe)) { //echo "read one K\n"; $data .= fread($r_pipe, 1024); } fclose($r_pipe); return $data; } function close_read() { return fclose($this->r_pipe); } /** * 删除管道 * * @return boolean is success */ function rm_pipe() { return unlink($this->fifoPath); } } /* 此类实现简单的管道通信*/ ?>
有关php中多线程的实现方法,请参考如下文章:
理解 php 多线程的妙用
php 多线程抓取网页的代码分享
php多线程(不使用fork)实例分享
php多线程类的代码分享
php支持多线程下载的例子
php支持socket,提供了socket的所有接口,可以实现一对一的通信。
php语言不支持线程,这里模拟了一个多线程代码(基于web服务器支持多线程)。
例子:
<?php /** * socket 多线程 * edit by www. */ function runThread() { $fp = fsockopen('localhost', 80, $errno, $errmsg); fputs($fp, "GET /a.php?act=brnrn"); //这里的第二个参数是HTTP协议中规定的请求头 //不明白的请看RFC中的定义 fclose($fp); } function a() { $fp = fopen('result_a.log', 'w'); fputs($fp, 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn"); fclose($fp); } function b() { $fp = fopen('result_b.log', 'w'); fputs($fp, 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn"); fclose($fp); } if(!isset($_GET['act'])) $_GET['act'] = 'a'; if($_GET['act'] == 'a') { runThread(); a(); } else if($_GET['act'] == 'b') b(); ?>
说明:
以上代码,虽然实现了多线程,但这些线程的通信是网页之间的通信,有session机制,http是无状态的协议,不保存用户信息,可以用session进行变量传递,而且,还有序列号,让变量序列号存在某个文件里面或者数据库里面,都是可以实现的。
socket_create/socket_accpet返回值都是一个resource指针。
serialize() 可处理除了 resource 之外的任何类型。
对于session传递,根本不可行,传递过去之后引用计数就随着之前的页面资源的卸载而销毁了。
页面传递是根本不可能传递资源类型的。
总结:
1,php要实现多线程,就得靠web服务器,本身没有,但是这样就必须要实现资源指针在网页之间互传。
2,资源指针是不能实现网页之间互传的。
在php编程中,有一种简单的方式可用于 Web 程序,即使用 fsockopen()、fputs() 来请求一个 URL, 而无需等待返回,然后在被请求的url中执行相关操作,即可看作异步执行的动作。
以下为关键代码:
/**
* 模拟多线程 异步执行
* edit by www.
*/
$fp = fsockopen('localhost',80,&$errno,&$errstr,5);
if(!$fp)
{
echo "$errstr ($errno)<br />/n";
}
fputs($fp,"GET another_page.php?flag=1/r/n");
fclose($fp);
?>
以上代码向页面 another_page.php 发送完请求就不管了,用不着等待请求页面的响应数据,利用这一点即可在被请求的页面 another_page.php异步传输数据。
有这样的应用例子,每当发表了一篇新日志后需要给所有该日志的订阅者发个邮件通知,一般方式为:
日志写完 -> 点提交按钮 -> 日志插入到数据库 -> 发送邮件通知 -> 告知撰写者发布成功
作者在点提交按钮到看到成功提示之间可能会等待很常时间,基本是在等邮件发送的过程,比如连接邮件服务异常、或器缓慢或是订阅者太多。
而实际上是不管邮件发送成功与否,保证日志保存成功基本可接受的,所以等待邮件发送的过程是很不经济的,这个过程可异步来执行,并且邮件发送的结果不太关心或以日志形式记录备查。
改进后的流程就:
└ 发送邮件通知 -> [记下日志]
以上是实现代码,包含两个文件,分别是 write.php 和 sendmail.php,在 sendmail.php 用 sleep(seconds) 来模拟程序执行所使用时间。
1,write.php,执行耗时 1 秒:
<?php
function asyn_sendmail()
{
$fp = fsockopen('localhost',80,&$errno,&$errstr,5);
if(!$fp)
{
echo "$errstr ($errno)<br />/n";
}
sleep(1);
fputs($fp,"GET /sendmail.php?param=1/r/n"); #请求的资源 URL 一定要写对
fclose($fp);
}
echo time().'<br>';
echo 'call asyn_sendmail<br>';
asyn_sendmail(); //www.
echo time().'<br>';
?>
2,sendmail.php,执行耗时 10 秒:
sleep(10);
fopen("C:/" . time(), "w");
?>
通过页面访问 write.php,页面输出:
call asyn_sendmail
1272472698
并且在 C:/ 生成文件:
1272472708
结果分析:
sendmail.php 至少花费 10 秒,但不会阻塞 write.php 继续往下执行,表明此过程是异步的。