在方法(类)中使用时,PHP套接字绑定/侦听不起作用

时间:2013-11-02 16:06:49

标签: php sockets bind listen

我想为几个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会说:

  1. $socket是一种资源(这就是我们想要的)
  2. $bind = true
  3. $listen = true
  4. 但代码实际上不是绑定/侦听。

    我做错了什么?

    修改

    经过测试:

    • PHP 5.4.4(Linux)
    • PHP 5.3.3(Linux)

1 个答案:

答案 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变量在其他任何地方都没有引用。