在单独的线程中运行方法

时间:2014-11-26 11:39:47

标签: php multithreading pthreads closures

我的服务器有方法SendToAll($ message)。我需要单独的线程,每秒都会运行此方法(SendToAll)。我正在使用pthreads。

class Sender extends Thread
{
    public function __construct($server)
    {
        $this->server = $server;
    }

    public function run()
    {
        for (;;) {
                $this->server->SendForAll("Hello");
                sleep(1);
            }
        }
    }
}

我创建服务器的对象并尝试将其放入发件人的构造中。

<?php
require_once('includes.php');

runServer();

function runServer()
{
    $server = new WssService("0.0.0.0", 9001);
    $asyncOp = new Sender($server);

    try {
        $asyncOp->start();
        $server->StartServer();
     }catch (Exception $e) {
        echo $e->getMessage();
        runServer();
    }
}

但我有错误

Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'Clos
ure' is not allowed' in D:\xampp\htdocs\admin_p\classes\AsyncStorage.php:6
Stack trace:
#0 D:\xampp\htdocs\admin_p\classes\AsyncStorage.php(6): Sender::__construct()
#1 D:\xampp\htdocs\admin_p\ss.php(9): Sender->__construct(Object(WssService))
#2 D:\xampp\htdocs\admin_p\ss.php(4): runServer()
#3 {main}
  thrown in D:\xampp\htdocs\admin_p\classes\AsyncStorage.php on line 6

P.S。对不起,英语 - 这不是我的母语。

class WssService
{
    public $connects_storage = array();
    private $server = null;
    private $logger = null;
    private $writer = null;
    public $loop = null;

    public function __construct($URI, $port)
    {

        $this->connected_users = array();
        $this->loop = \React\EventLoop\Factory::create();
        $this->Logger = new \Zend\Log\Logger();
        $this->writer = new Zend\Log\Writer\Stream("php://output");
        $this->Logger->addWriter($this->writer);
        $this->server = new WebSocketServer("tcp://" . $URI . ":" . $port, $this->loop, $this->Logger);

        $this->server->on("connect", function (WebSocketTransportInterface $user) {
            $this->Logger->notice((" Connected " . $user->getIp()));
            array_push($this->connects_storage,$user);
        });

        $this->server->on("disconnect", function (WebSocketTransportInterface $user) {
            $this->Logger->notice((" Disconnected " . $user->getIp()));
        });

        $this->server->on("message", function (WebSocketTransportInterface $s_user, WebSocketMessageInterface $message) {
            $s_user->sendString($message);
        });
    }

    public function StartServer(){
        $this->server->bind();
        $this->loop->run();
    }

    public function SendForAll($message){
        foreach($this->connects_storage as $client){
        $client->sendString($message);
        }
    }
}

更新方法SendForAll()

public function SendForAll($message){
        echo var_export($message,true) .PHP_EOL;
        echo var_dump($this->connects_storage).PHP_EOL;

        if (count($this->connects_storage) > 0) {
            foreach ($this->connects_storage as $client) {
                $client->sendString($message);
            }
        } else echo "There are empty storage";
    }

2 个答案:

答案 0 :(得分:-1)

$this->server->on("connect", function (WebSocketTransportInterface $user) {
    $this->Logger->notice((" Connected " . $user->getIp()));
    array_push($this->connects_storage,$user);
});

$this->server->on("disconnect", function (WebSocketTransportInterface $user) {
    $this->Logger->notice((" Disconnected " . $user->getIp()));
});

$this->server->on("message", function (WebSocketTransportInterface $s_user, WebSocketMessageInterface $message) {
    $s_user->sendString($message);
});

匿名函数/闭包无法序列化。您需要找出一种以不同方式存储它们的方法。

编辑:我花了一些时间来测试这段代码,(原来你不能用最新的php使用pthreads)。无论如何,我通过执行以下操作来解决您的问题:

将上面的代码替换为:

$this->server->on("connect", new Jeremeamia\SuperClosure\SerializableClosure(function (WebSocketTransportInterface $user) {
    $this->Logger->notice((" Connected " . $user->getIp()));
    array_push($this->connects_storage,$user);
}));

$this->server->on("disconnect", new Jeremeamia\SuperClosure\SerializableClosure(function (WebSocketTransportInterface $user) {
    $this->Logger->notice((" Disconnected " . $user->getIp()));
}));

$this->server->on("message", new Jeremeamia\SuperClosure\SerializableClosure(function (WebSocketTransportInterface $s_user, WebSocketMessageInterface $message) {
    $s_user->sendString($message);
}));

完成后,您需要包含正确的library,并且可能包含正确的文件(我总是无法让作曲家正确地自动加载内容)

答案 1 :(得分:-1)

您的WssService对象不可序列化。为此,请制作$URL$port成员变量,将初始化移至init()方法,并实施__sleep()__wakeup()方法:

class WssService
{
    protected $URI, $port;
    public $connects_storage = array();
    private $server = null;
    private $logger = null;
    private $writer = null;
    public $loop = null;

    public function __construct($URI, $port)
    {
        $this->URI = $URI;
        $this->port = $port;
        $this->init();
    }
    protected function init() {
        $this->connected_users = array();
        $this->loop = \React\EventLoop\Factory::create();
        $this->Logger = new \Zend\Log\Logger();
        $this->writer = new Zend\Log\Writer\Stream("php://output");
        $this->Logger->addWriter($this->writer);
        $this->server = new WebSocketServer("tcp://" . $this->URI . ":" . $this->port, $this->loop, $this->Logger);

        $this->server->on("connect", function (WebSocketTransportInterface $user) {
            $this->Logger->notice((" Connected " . $user->getIp()));
            array_push($this->connects_storage,$user);
        });

        $this->server->on("disconnect", function (WebSocketTransportInterface $user) {
            $this->Logger->notice((" Disconnected " . $user->getIp()));
        });

        $this->server->on("message", function (WebSocketTransportInterface $s_user, WebSocketMessageInterface $message) {
            $s_user->sendString($message);
        });
    }

    public function StartServer(){
        $this->server->bind();
        $this->loop->run();
    }

    public function SendForAll($message){
        foreach($this->connects_storage as $client){
        $client->sendString($message)
        }
    }
    public function __sleep() {
        return array('URI', 'port');
    }
    public function __wakeup() {
        $this->init();
    }
}

__sleep()告诉序列化程序仅序列化$URI$port个变量,这就是在反序列化过程中调用init()__wakeup()所需的全部内容。