You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发PHP简易聊天时,多客户端能否同时接收同一PHP进程经SSE/AJAX发送的数据?

核心问题本质

你现在遇到的「每个SSE连接独立运行一次PHP脚本、状态完全隔离」,是PHP传统Web运行模式(PHP-FPM/Apache mod_php)的固有特性,不是代码逻辑写错了。
PHP传统模式的设计逻辑就是「请求进来 → 分配一个独立工作进程 → 跑完请求逻辑 → 销毁进程释放资源」,天生没有跨进程的内存共享、广播能力。你原来的代码里每个连接自己存$number变量从0开始数,哪怕100个客户端连进来,100个进程各自维护各自的计数,不仅两个客户端看到的数字根本不同步,每个进程还占一份系统资源,连接数多了自然会把服务器打满。

适配「不安装额外服务软件」需求的零依赖实现方案

要实现“所有客户端接收同源推送的同步内容”,不需要硬让所有客户端挤在一个PHP进程里跑,只要把「全局状态生成」和「客户端消息推送」拆离,用PHP本身就支持的本地文件做跨进程的公共存储层,就能达到和单进程推送完全一致的效果,全程不需要装Redis、队列、WebSocket服务这类额外软件。
实现逻辑分两部分:

  • 单独跑一个CLI模式的PHP脚本作为唯一的状态源头,负责持续更新全局数字,把最新状态写到共享文件里,这个脚本只需要启动一次,永久在后台运行。
  • 原来的SSE接口不再自己维护状态,每个连接只需要从共享文件里读最新的全局状态,推给当前连接的客户端。不管多少个客户端连进来,读的都是同一个文件的内容,看到的数字完全同步,效果上和单进程推送没有区别。

具体代码实现

  1. 后台常驻的状态生成脚本 state_generator.php

    <?php
    // 仅支持CLI模式运行,不要通过web访问
    $sharedFile = __DIR__ . '/shared_state.txt';
    $number = 0;
    while(true) {
        $fp = fopen($sharedFile, 'c+');
        // 加排他锁避免读写冲突
        if(flock($fp, LOCK_EX)) {
            ftruncate($fp, 0);
            fwrite($fp, $number);
            flock($fp, LOCK_UN);
        }
        fclose($fp);
        $number++;
        sleep(1);
    }
    

    启动方式也不需要额外软件,用Linux系统自带的nohup命令就能后台挂起:
    nohup php state_generator.php > /dev/null 2>&1 &

  2. 修改后的SSE推送接口 myFile.php

    <?php
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    $sharedFile = __DIR__ . '/shared_state.txt';
    // 取消脚本执行时间限制
    set_time_limit(0);
    while(true) {
        $number = 0;
        // 读共享文件的最新状态
        if(file_exists($sharedFile)) {
            $fp = fopen($sharedFile, 'r');
            // 加共享锁保证读到完整内容
            if(flock($fp, LOCK_SH)) {
                $number = intval(fread($fp, 1024));
                flock($fp, LOCK_UN);
            }
            fclose($fp);
        }
        echo "data: $number\n\n";
        @ob_flush();
        flush();
        sleep(1);
    }
    
  3. 你原来的client.html完全不需要改动,直接打开多个页面测试,就能看到所有页面的数字是同步递增的,和期望的统一推送效果一致。

方案注意事项

  • 这个方案本质上还是每个SSE连接占一个PHP-FPM的工作进程,所以需要把PHP-FPM的pm.max_children参数调高,适配长连接的数量,不然连接数超过进程池上限就会无法响应。
  • 高并发下文件读写的性能会有瓶颈,适合你一开始想做的小规模简易聊天场景。
真·单进程全连接处理的实现方式

如果后续连接数上来,想要完全实现「单个PHP进程挂所有客户端连接、统一推送,不占用PHP-FPM的进程资源」的效果,只需要用Workerman即可:这个框架是纯PHP编写的常驻进程库,不需要安装任何系统级服务,通过Composer安装后,就能在单个PHP进程里同时监听所有客户端的SSE连接,把所有连接对象存在进程内存里,后台定时器统一生成消息,遍历所有连接推送给客户端,不管10个还是1000个客户端连接,都只占一个PHP进程的资源,资源占用比之前的文件共享方案低很多。

这个方案的核心是跳出PHP传统的web请求模型,用PHP的网络库自己实现HTTP服务能力,不需要依赖Nginx/Apache的转发,自然也就没有每个连接分配一个PHP-FPM进程的问题。

内容的提问来源于stack exchange,提问作者Guillermo P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 12:06:11