我想为几个cron作业实现一个简单的锁定机制,并决定以不寻常的方式进行。看来,对于socket create / bind / listen来说,PHP有点儿麻烦。
正在运行的代码:
<?php
echo 'EXECUTING: '. __METHOD__ . \PHP_EOL;
if(false === ($socket = \socket_create(\AF_INET, \SOCK_STREAM, \SOL_TCP))) {
die('create');
}
if(false === ($bind = \socket_bind($socket, '127.0.0.1', 4444))) {
die('bind');
}
if(false === ($listen = \socket_listen($socket))) {
die('listen');
}
var_dump($socket, $bind, $listen);
这将创建一个套接字,将其绑定到接口等待传入连接。 你可以通过调用来检查它:
netstat -anp | grep LIST | grep tcp
如果您使用相同的PHP代码并将其放入一个简单的类中,它将不会绑定/侦听。这是我正在谈论的代码:
<?php
class Test
{
public function lock()
{
echo 'EXECUTING: '. __METHOD__ . \PHP_EOL;
if(false === ($socket = \socket_create(\AF_INET, \SOCK_STREAM, \SOL_TCP))) {
die('create');
}
if(false === ($bind = \socket_bind($socket, '127.0.0.1', 4444))) {
die('bind');
}
if(false === ($listen = \socket_listen($socket))) {
die('listen');
}
var_dump($socket, $bind, $listen);
}
}
$t = new Test();
$t->lock();
echo 'Working...'. \PHP_EOL;
sleep(60);
echo 'Done.';
执行此代码,您将看到var_dump会说:
$socket
是一种资源(这就是我们想要的)$bind = true
$listen = true
但代码实际上不是绑定/侦听。
我做错了什么?
修改
经过测试:
答案 0 :(得分:3)
答案很简单:您的$socket
变量是本地变量,它没有引用,而是在方法范围内。这意味着,一旦执行了方法,PHP将销毁所有局部变量 - 所以$socket
也是如此。 I. e。你正在成功创建套接字,然后PHP在同一时刻取消设置(因为方法结束了它的执行)。请注意,取消设置局部变量并不意味着无意中释放内存。垃圾收集周期很昂贵,因此只有在达到内存限制时PHP才会这样做。
要查看差异,请在创建套接字后在方法内部调用sleep()
。从版本5.3开始,PHP有garbage collection,因此您尝试过的版本会受到影响。要实时查看,您可以查看this snippet:
class Foo
{
public function __destruct()
{
echo('destroyed'.PHP_EOL);
}
}
class Bar
{
public function test()
{
echo('starting method'.PHP_EOL);
$obj = new Foo();
echo('ending method'.PHP_EOL);
}
}
echo('start script'.PHP_EOL);
$obj = new Bar;
$obj->test();
echo('end script'.PHP_EOL);
结果
start script starting method ending method destroyed end script
- 你可以看到,在退出方法调用之后,类析构函数被立即调用,因为本地$obj
变量在其他任何地方都没有引用。