php脚本 - 将输入重定向到另一个实例

时间:2016-10-08 15:29:54

标签: php io pipe flock

我有一个php脚本,如果脚本已经运行,则使用flock()拒绝多个实例。

我希望脚本调用中提供的参数转移到能够处理它们的现有进程。

即:

test.php:

#!/usr/bin/env php
<?php

$lock_file = fopen ( getcwd () . '/'. basename(__FILE__, '.php') . '.pid', 'c' );
$got_lock = flock ( $lock_file, LOCK_EX | LOCK_NB, $wouldblock );
if ($lock_file === false || (! $got_lock && ! $wouldblock)) :
    throw new Exception ( "Error opening or locking lock file" );
    error_log("execption thrown");
elseif (! $got_lock && $wouldblock) :
    exit ( "Another instance is already running; terminating.\n" );
endif;

while (true) :
    $input = $argv; // or incomming datas from other script ?
    unset($argv);
    if (is_array($input)) :
        foreach ($input as $a) :
            echo $a;
        endforeach;
    else :
        echo $input;
    endif;
endwhile;

?>

现在,如果我跑:

php -f test.php arg1 arg2

php -f test.php arg3 arg4

第二个调用也退出了,但我希望arg3和arg4通过管道进入主进程。

我该怎么做?

1 个答案:

答案 0 :(得分:1)

换句话说,您想要一种与已存在的流程进行通信的方法吗?又称IPC,有很多方法可以做到这一点。共享内存的绝对最快方式。但是使用数据库或unix套接字会更容易实现。这是一个使用SQLite的例子:

只要方便处理消息,请执行以下操作:

while(NULL!==($message=check_for_message())){//handle all messages
echo "got a mesage!:";
var_dump($message);
}

和“check_for_message”功能:

//returns string("message") if there is a message available.
// else returns NULL
//Warning, do not try to optimize this function with prepared statements, unless you know what you're doing, in SQLIte they will lock the database from writing.
function check_for_message(){
static $db=false;
if($db===false){
$db=new PDO('sqlite:ipc.db3','','',array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$db->exec(
'
CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY AUTOINCREMENT, message TEXT);

'
);
register_shutdown_function(function()use(&$db){
$db=NULL;
unset($db);
unlink("ipc.db3");
});
}
$message=$db->query("SELECT id,message FROM messages LIMIT 1",PDO::FETCH_ASSOC);

foreach($message as $ret){
$db->query("DELETE FROM messages WHERE id = ".$db->quote($ret['id']));
return $ret['message'];
}
return NULL;
}

并发送消息:

示例用法:

foreach($argv as $arg){
sendmessage($arg);
}

功能:

function sendmessage(string $message){
$db=new PDO('sqlite:ipc.db3','','',array(
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));
$db->query('INSERT INTO messages (message) VALUES('.$db->quote($message).');');
}

注意:我认为您可以通过使用WAL模式sqlite和预处理语句来优化该功能。我认为你可以通过使用PDO :: ATTR_PERSISTENT将它放在共享内存中来进一步优化它,但是afaik,这是使用未记录的功能的hackish,我不希望它适用于像HHVM PHP这样的东西。在unixes(* BSD,Mac OS X,Linux等)上,使用unix套接字无论如何都会更快。使用原始共享内存会更快,但在共享内存中实现消息队列有点棘手.. 您还可以考虑安装信号处理程序,例如,SIGUSR1以指示有消息在等待,请参阅http://php.net/manual/en/function.pcntl-signal.php