如何在PHP/Windows中通知用户异步任务结束

如何在PHP/Windows中通知用户异步任务结束,php,windows,asynchronous,publish-subscribe,Php,Windows,Asynchronous,Publish Subscribe,考虑下图: 思想 用户可以执行单个文件/批上传(我知道HTTP规范),批是指某人可以一次发送多个文件 图像上传服务旨在为每个发送的文件创建一个子进程(图像处理器) 问题 那么,什么样的客户机-服务器通信方法最适合将这些子进程的通知发送回客户机 创建子进程的最佳方法是什么?我读过关于proc\u open,curl方法的书。我不知道如何使用消息队列(如果它适用的话) 注释 我要说的是,我正在ASP.NET中使用Windows操作系统(Windows Server 2008)和XAMPP,这是很容

考虑下图:

思想

  • 用户可以执行单个文件/批上传(我知道HTTP规范),批是指某人可以一次发送多个文件
  • 图像上传服务旨在为每个发送的文件创建一个子进程(图像处理器)
  • 问题

  • 那么,什么样的客户机-服务器通信方法最适合将这些子进程的通知发送回客户机
  • 创建子进程的最佳方法是什么?我读过关于
    proc\u open
    curl
    方法的书。我不知道如何使用消息队列(如果它适用的话)
  • 注释


    我要说的是,我正在ASP.NET中使用Windows操作系统(
    Windows Server 2008
    )和
    XAMPP

    ,这是很容易做到的。下面是一个在ASP.NET中实现的示例

    但是,由于您希望在PHP/windows中完成,因此可以通过几种方法来完成

    为什么不能让imageprocessing在完成后更新数据库表或会话中的某些字段,并从HTML页面保留一个javascript计时器,用于轮询数据库/会话变量的可能状态?一旦从db/session(由图像处理逻辑更新)获得完成状态,javascript计时器可以采取进一步的操作吗


    希望这有帮助。

    为了在文件上传过程中实现正确的客户机-服务器通信,我们通常在jQuery中使用AJAX(异步JS)。 发送任何需要的数据,在您的情况下,这些数据将是文件详细信息。在服务器(PHP)上执行操作,完成后将json响应发送回客户机以进行通知。 关键是,您需要在AJAX的success函数中获得子进程的响应。只有在成功完成后,通知才会到达。

    您可以查看

    它已经有了和libs


    因为并非所有浏览器都支持套接字,所以您应该小心使用它,或者为旧浏览器提供任何备用功能

    用户上载图像。完成此步骤后,可以创建任务。一个Taks是数据库中任务表中的一行

    class Task
    {
        const STATUS_PENDING = 'pending'
        const STATUS_ERROR = 'error'
        const STATUS_FINISHED = 'finished'
    
        private $userid;
        private $taskData = array();
    
        public function run()
        {
            // create process
        }
    
        public function update()
        {
            // update the status an other changes you need to the database
            // or any other storage you use.
        }
    
        public function getStatus();
    }
    
    class TaskManager
    {
        const MAX_TASKS = 5;
        private $tasks = array();
    
        public function addTaks();
        public function start()
        {
            foreach ($tasks as $task) {
                $task->run();
            }
        }
    }
    
    在服务器端,您必须考虑如何工作/组织任务。这取决于你的需要。借助TaskManager的强大功能,您可以 控制你的过程。这是非常重要的,不是100个进程并行运行

    客户端现在可以使用userid轻松地请求任务表检查挂起的任务。如果状态为“已完成”或“错误”,则可以向用户提供 非常好的反馈。您可以每五秒钟轮询一次此信息。间隔时间取决于你的需要。5秒以下的投票对于您的客户来说可能是很奇怪的 浏览器最好由客户机获取状态,而不是由服务器将状态发送给客户机。如果服务器发送您必须使用web套接字的状态很重要。后端可以相同

    下面是一个简单的轮询示例

    setInterval(function(){
        $.ajax({ url: "server", success: function(data){
            //Update your dashboard gauge
            salesGauge.setValue(data.value);
        }, dataType: "json"});
    }, 30000);
    
    class Task
    {
        private $process = null;
        private $pipes = array();
        private $status = 'pending'
    
        public function run()
        {
            $descriptor = array (
                0 => array("pipe", "r"),
                1 => array("pipe", "w"),
                2 => array("pipe", "w")
            );
    
            $cmd = "/path/to/progam --with --some-arguments"
    
            $this->process = proc_open($command, $descriptor, $this->pipes);
            stream_set_blocking($this->pipes[1], 0);
        }
    
        public function close()
        {
            foreach($this->pipes as $pipe) {
                fclose($pipe);
            }
    
            $exitStatus = proc_close($this->process);
    
            $this->process = NULL;
    
            return $exitStatus;
        }
    }
    
    只有当您有一些高级选项时,proc_open才是好的。使用
    proc\u open
    (注意管道)的功能,并结合流设置阻塞。 您可以编写异步任务处理。如果您不需要一些特殊的
    exec
    就足够了

    下面是一个非阻塞示例

    setInterval(function(){
        $.ajax({ url: "server", success: function(data){
            //Update your dashboard gauge
            salesGauge.setValue(data.value);
        }, dataType: "json"});
    }, 30000);
    
    class Task
    {
        private $process = null;
        private $pipes = array();
        private $status = 'pending'
    
        public function run()
        {
            $descriptor = array (
                0 => array("pipe", "r"),
                1 => array("pipe", "w"),
                2 => array("pipe", "w")
            );
    
            $cmd = "/path/to/progam --with --some-arguments"
    
            $this->process = proc_open($command, $descriptor, $this->pipes);
            stream_set_blocking($this->pipes[1], 0);
        }
    
        public function close()
        {
            foreach($this->pipes as $pipe) {
                fclose($pipe);
            }
    
            $exitStatus = proc_close($this->process);
    
            $this->process = NULL;
    
            return $exitStatus;
        }
    }
    
    我希望这会给你一些灵感来解决你的问题。 对于真正的消息队列,您可以使用您想要的。我是一个粉丝,现在我将停止讨论解决方案和想法,因为这个问题
    更复杂,我可以再写100页。如果你有问题,你可以写一行

    最好的方法是利用消息队列,例如ActiveMQ、RabbitMQ等。然后将执行以下步骤:

  • 上传文件到服务器,最好是通过nginx(PHP速度慢,无法有效处理多次上传)
  • 调用将准备所有信息并将其作为任务存储到MQ中的PHP代码。还返回浏览器将使用的事件订阅(nginx推送模块)的唯一路径。这可以是WebSocket或长轮询通道,请选择一个您熟悉的通道
  • PHP守护进程连接到MQ并执行图像的多线程处理,将信号发送回nginx推送模块,以通知浏览器任务完成
  • 显示用户通知框并取消订阅推送频道

  • 是的,谢谢,我一直在考虑实施某种形式的长轮询过程。关于发布/订阅模式或消息队列,您能说些什么?你试过了吗?我看过一些关于如何在*nix系统上使用PHP的文章。也许是使用?