PHP - 服务器之间的套接字通信

时间:2017-03-14 12:49:13

标签: php apache sockets

经过多年在其他人的帖子中寻找答案,我终于要问了。
我正在尝试实现一个WatchDog / Shepherd模式来监视在我的应用程序中运行的长进程(从2-3分钟到几个小时)。 该应用程序相当复杂,我在项目中期开始研究它,所以我没有完全掌握它。
两台服务器正在运行:我们称之为FACADE,Apache / 2.4.10(Debian)和CALCULUS,以及Apache / 2.4.6(Red Hat Enterprise Linux)。 我设计了这样的东西:  

  • 当用户点击触发漫长过程的按钮时,Shepherd会在FACADE上初始化
  •  
  • 在CALCULUS上运行的进程初始化一个使用TCP套接字连接到Shepherd的WatchDog。
  •  
  • 在这个过程的一些关键点,WatchDog'吠叫',即向Shepherd发送一个字符串,告诉他Process在哪一步(字符串就像“M(essage)#S(tarting)#Indexing “,”M#C(完成)#Indexing“,”M#S#Transfert“,”M#C#Transfert“......)如果出现错误(在这种情况下它会发送”E#Indexing“= >索引期间发生错误)
  •  
  • 当他从狗那里收到消息时,Shepherd会做他必须做的事情(处理,向用户显示,填写一点进度条......)
  • 我的朋友,纯粹是理论。现在来了实施:

    /**
     *Implements the Singleton Design Pattern
     *And of course, the Watchdog Pattern, using a Socket to communicate with the Shepherd.
     */
    class Watchdog{
    
        /** Singleton Design pattern. Use $watchdog = Watchdog::getInstance() to use the doggy */
        private static $instance = null;
    
        private function __construct(){
                $this->init();
        }
        public static function getInstance(){
                if (Watchdog::$instance === null)
                        Watchdog::$instance = new Watchdog();
    
                return Watchdog::$instance;
        }
    
        private $socket;
        private $connected = false;
    
        private function init(){
                $this->socket = fsockopen("tcp://A.B.C.D", 4242, $errno, $errstr);
                if($this->socket === false){
                        echo "$errno : $errstr";
                }else{
                        $this->connected = true;
                }
        }
    
        public function kill(){
                fclose($this->socket);
                Watchdog::$instance = null;
        }
    
    
    
        public function bark($message){
                if($this->connected === true){
                fwrite($this->socket, "M#".$message."\n");
                }
        }
    
        public function alert($err){
                if($this->connected === true){
                        fwrite($this->socket, "E#".$err."\n");
                }
        }
    
    }
    
    ?>
    

    Shepeherd:

    /**Implements the Singleton Design Pattern,
     * And the Shepherd / Watchdog Patter, using a Socket to communicate with the Watchdog.
     */
    class Shepherd{
    
        /** Singleton Design pattern. Use $shepherd = Shepherd::GetInstance() to use the shepherd */
        private static $instance;
    
        private function __construct()
        {
                $this->init();
        }
        public static function GetInstance(){
                if (self::$instance === null)
                        self::$instance = new Shepherd();
    
                return self::$instance;
        }
    
    /**Instance variables **/
        private $socket;
        public $initialised = false;
        public $doggyConnected = false;
        private $dogsocket;
    
    /**Init : Initializes the shephrd by binding it to the watchdog on the 4242 port**/
        private function init(){
    
                ob_implicit_flush();
                $this->socket = stream_socket_server("tcp://0.0.0.0:4242", $errno, $errstr);
                $this->initialised = true;
        }
    
    /**Sit And Wait : Waits for Dog connection**/
        public function sitandwait(){
                //Waiting for doggy connection
                do {
                        if (($this->dogsocket = stream_socket_accept($this->socket)) === false) {
                                echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($this->dogsocket)) . "\n";
                                break;
                        }else{
                                $this->doggyConnected = true;
                        }
                }while($this->doggyConnected === false);
        }
    
    /**Listen to Dog : Waits for Dog to send a message and echoes it **/
        public function listentodog(){
                if($this->dogsocket !== false) {
                                $buf = fgets($this->dogsocket);
                                return $buf;
                }
        }
    
    /**Kill : Kills the shepherd and closes connections **/
    
        private function kill(){
                stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
                stream_socket_shutdown($this->dogsocket, STREAM_SHUT_RDWR);
                fclose ($this->dogsocket);
                fclose ($this->socket);
                Shepherd::$instance = null;
        } 
    
       /**Run : Runs the Shepherd till he got a message from dog **/
        public  function run(){
       if($this->doggyConnected === false)
                        $this->sitandwait();
                return $this->listentodog();
        }
    
    
    }
    

    在真正的网站上尝试了那些没有成功之后,我决定试着看看两台服务器上发生了什么,多亏了netcat命令。
    有一个问题:当我通过netcat伪造牧羊人时,狗可以连接并发送有关过程的准确数据。当我通过netcat --send-only伪造狗时,Shepherd获取数据并用它们做正确的事情。
    但是,当我从应用程序中运行时,我得到了一个“Connexion拒绝”的狗 - > init()(fsockopen:Connexionrefusée),当然,牧羊人死于超时。
    但等等还有更多!! 您可能认为问题来自连接,而netcat则没有出现因为我没有从PHP连接(或者我没有连接)到PHP打开的套接字)。 我也这么认为;我编写了两个脚本test_dog.php和test_shepherd.php,它们的使用方式与我实际应用程序中的方式完全相同。当我试图让他们沟通时,它的作用!它甚至适用于真正的狗(监控真实的应用程序进程)和test_shepherd.php,或者使用真正的Shepherd(来自我的应用程序)和test_watchdog.php

    我决定来这里向你们求助,因为我完全迷失了。我不明白为什么它不能与真正的代码一起使用,而是与test_脚本一起使用。在那些中,我确保使用与实际应用程序完全相同的方式。

    为了向您展示一切,这是我的test_脚本:
    test_watchdog.php

    require "Watchdog.php";
    
    $dog = Watchdog::getInstance();
    $dog->bark("Try try try");
    $dog->bark("Trying hard !!");
    sleep(5);
    $dog->bark("Trying harder to see...");
    sleep(2);
    $dog->bark("END");
    $dog->kill();
    

    test_shepherd.php

    require "Shepherd.php";
    
    $shep = new _Shepherd();
    echo $shep->run();
    

    ......我认为这就是全部。请回答你是否有可能帮助我的最微弱的想法,你是我最后的希望,我迷失了,绝望...... 提前谢谢你:)

    编辑:在CALCULUS上,Watchdog由一个名为Process(运行主进程)的千行长类调用。关键是能够在代码中的几乎所有位置调用Watchdog,用户可能必须等待。
    这里是例如Process的__construct,初始化Watchdog,以及调用$ doggy-> bark()的方法之一;

     public function __construct($photoId = 0) {
            $this->params = array();
            $this->doggy = Watchdog::GetInstance();
    
            $this->params['photoid'] = $photoId ;
    
            date_default_timezone_set ('Europe/Paris');
    }
    
    public function transfertProject() {
        try {
        $this->doggy->bark('s#transfert');
        //Traitement long
        set_time_limit (0);
        ini_set('post_max_size', 0);
        ini_set('upload_max_filesize', 0);
        $response = false;
    
        if (!isset($_FILES['file'])) {
            $post_max_size = ini_get('post_max_size');
            $upload_max_size = ini_get('upload_max_filesize');
            return "Le fichier ne semble pas avoir été posté,  vérifier la taille maximal d'upload";
        }
        $name = $_FILES['file']['name'];
        $filename = "../Workspace/projects/".$name;
        $tmp = $_FILES['file']['tmp_name'];
        if (move_uploaded_file($_FILES['file']['tmp_name'], $filename)) {
            $response = $this->unzipProjectArchive();
            unlink($filename);
        }
        $this->doggy->bark('c#transfert');
        return $response;
      } // END TRY
       catch (Exception $ex)  {
       //Watchdog telling shepherd
       $this->doggy->alert('transfert');
    }
    }
    

    0 个答案:

    没有答案