导读:本期聚焦于小伙伴创作的《PHP实现消息推送的几种方案详解:从短轮询、长轮询到WebSocket与第三方服务》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《PHP实现消息推送的几种方案详解:从短轮询、长轮询到WebSocket与第三方服务》有用,将其分享出去将是对创作者最好的鼓励。

PHP实现消息推送的几种方案

消息推送是Web应用中常见的功能需求,比如实时通知、订单状态更新、聊天消息同步等场景都需要用到。PHP作为服务端常用语言,本身不支持长连接特性,但可以通过多种方案实现消息推送能力。本文将介绍几种主流的PHP消息推送实现方案,并附带对应的代码示例。

一、短轮询(Short Polling)

短轮询是最简单的消息推送实现方式,原理是客户端每隔固定时间向服务端发送请求,查询是否有新消息,服务端返回当前是否有未读消息的结果。

这种方案实现成本低,但存在明显的缺点:如果轮询间隔过短,会增加服务端请求压力;如果间隔过长,消息实时性会变差,适合消息实时性要求不高、并发量较小的场景。

实现示例

服务端PHP代码(polling_server.php):

<?php
// 模拟消息存储,实际项目中可替换为数据库、Redis等存储
$messages = [
    ['id' => 1, 'content' => '您有新的订单待处理', 'is_read' => 0],
    ['id' => 2, 'content' => '系统将于今晚23点维护', 'is_read' => 0]
];

// 获取客户端已读消息ID
$lastReadId = isset($_GET['last_read_id']) ? intval($_GET['last_read_id']) : 0;

// 查询未读消息
$unreadMessages = [];
foreach ($messages as $msg) {
    if ($msg['id'] > $lastReadId && $msg['is_read'] == 0) {
        $unreadMessages[] = $msg;
    }
}

header('Content-Type: application/json; charset=utf-8');
echo json_encode([
    'code' => 0,
    'data' => $unreadMessages,
    'last_id' => $lastReadId
]);

客户端JavaScript代码:

let lastReadId = 0;
// 每5秒轮询一次
setInterval(() => {
    fetch('polling_server.php?last_read_id=' + lastReadId)
        .then(res => res.json())
        .then(data => {
            if (data.code === 0 && data.data.length > 0) {
                data.data.forEach(msg => {
                    console.log('收到新消息:', msg.content);
                    lastReadId = msg.id;
                });
            }
        });
}, 5000);

二、长轮询(Long Polling)

长轮询是对短轮询的优化,客户端发送请求后,服务端如果没有新消息,会保持连接不返回,直到有新消息或者连接超时,再返回结果给客户端,客户端收到响应后立即发起下一次请求。

这种方案减少了无效请求的数量,实时性比短轮询更好,适合中等并发、对实时性有一定要求的场景,但长时间保持连接会占用服务端资源。

实现示例

服务端PHP代码(long_polling_server.php):

<?php
// 设置脚本执行时间,避免过早超时
set_time_limit(30);
// 关闭输出缓冲
ob_end_clean();

// 模拟消息存储,实际项目可替换为Redis订阅、数据库监听等
function hasNewMessage($lastReadId) {
    // 模拟检查新消息,实际中可查询存储
    $newMessages = [
        ['id' => 3, 'content' => '您的退款已到账', 'time' => time()]
    ];
    foreach ($newMessages as $msg) {
        if ($msg['id'] > $lastReadId) {
            return $msg;
        }
    }
    return false;
}

$lastReadId = isset($_GET['last_read_id']) ? intval($_GET['last_read_id']) : 0;
$timeout = 25; // 最长等待25秒
$startTime = time();

while (time() - $startTime < $timeout) {
    $newMsg = hasNewMessage($lastReadId);
    if ($newMsg) {
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode([
            'code' => 0,
            'data' => $newMsg
        ]);
        exit;
    }
    // 休眠1秒再检查,减少CPU消耗
    sleep(1);
}

// 超时无新消息,返回空结果
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
    'code' => 0,
    'data' => null
]);

客户端JavaScript代码:

let lastReadId = 0;
function longPolling() {
    fetch('long_polling_server.php?last_read_id=' + lastReadId)
        .then(res => res.json())
        .then(data => {
            if (data.code === 0 && data.data) {
                console.log('收到新消息:', data.data.content);
                lastReadId = data.data.id;
            }
            // 立即发起下一次长轮询
            longPolling();
        })
        .catch(err => {
            // 请求失败1秒后重试
            setTimeout(longPolling, 1000);
        });
}
// 启动长轮询
longPolling();

三、WebSocket协议

WebSocket是全双工通信协议,建立连接后客户端和服务端可以双向实时通信,不需要反复建立HTTP连接,实时性最好,适合聊天、实时数据监控等高并发、高实时性要求的场景。

原生PHP本身不支持WebSocket服务,需要借助Swoole、Workerman等扩展来实现服务端能力。

基于Workerman的实现示例

首先需要安装Workerman扩展,可通过Composer执行composer require workerman/workerman安装。

服务端PHP代码(websocket_server.php):

<?php
require_once __DIR__ . '/vendor/autoload.php';
use WorkermanWorker;

// 创建一个WebSocket服务,监听8080端口
$ws_worker = new Worker('websocket://0.0.0.0:8080');

// 启动4个进程处理请求
$ws_worker->count = 4;

// 存储客户端连接
$connections = [];

// 客户端连接时的回调
$ws_worker->onConnect = function($connection) use (&$connections) {
    $connections[$connection->id] = $connection;
    echo "客户端连接成功,ID:{$connection->id}n";
};

// 收到客户端消息时的回调
$ws_worker->onMessage = function($connection, $data) use (&$connections) {
    $msgData = json_decode($data, true);
    if ($msgData['type'] === 'push') {
        // 向所有客户端推送消息
        foreach ($connections as $conn) {
            $conn->send(json_encode([
                'type' => 'message',
                'content' => $msgData['content'],
                'time' => date('Y-m-d H:i:s')
            ]));
        }
    }
};

// 客户端断开连接时的回调
$ws_worker->onClose = function($connection) use (&$connections) {
    unset($connections[$connection->id]);
    echo "客户端断开连接,ID:{$connection->id}n";
};

// 运行服务
Worker::runAll();

客户端JavaScript代码:

const ws = new WebSocket('ws://127.0.0.1:8080');

ws.onopen = function() {
    console.log('WebSocket连接成功');
    // 模拟发送推送请求
    ws.send(JSON.stringify({
        type: 'push',
        content: '这是一条测试推送消息'
    }));
};

ws.onmessage = function(e) {
    const data = JSON.parse(e.data);
    console.log('收到推送消息:', data.content, ',时间:', data.time);
};

ws.onerror = function(err) {
    console.log('WebSocket连接出错:', err);
};

ws.onclose = function() {
    console.log('WebSocket连接关闭');
};

启动服务只需要执行命令php websocket_server.php start即可。

四、第三方推送服务集成

如果不想自己维护推送服务,也可以集成第三方推送平台,比如接入https://www.ipipp.com提供的推送接口,服务端调用接口发送消息,第三方服务负责将消息推送到客户端。

这种方案不需要自己处理长连接、高并发等问题,开发成本低,适合中小项目快速实现推送功能,缺点是依赖第三方服务,可能存在费用或者服务稳定性风险。

实现示例

服务端调用第三方推送接口示例:

<?php
/**
 * 调用第三方推送接口发送消息
 * @param string $targetId 目标用户ID
 * @param string $content 消息内容
 * @return bool
 */
function sendPush($targetId, $content) {
    $apiUrl = 'https://www.ipipp.com/api/push/send';
    $appKey = 'your_app_key';
    $appSecret = 'your_app_secret';
    
    $postData = [
        'target_id' => $targetId,
        'content' => $content,
        'timestamp' => time(),
        'nonce' => uniqid()
    ];
    // 生成签名,实际接口需按照第三方要求的签名规则生成
    $postData['sign'] = md5($appKey . $postData['timestamp'] . $appSecret . $postData['nonce']);
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    $result = json_decode($response, true);
    return isset($result['code']) && $result['code'] == 0;
}

// 调用示例
$res = sendPush('user123', '您有新的系统通知');
if ($res) {
    echo '推送发送成功';
} else {
    echo '推送发送失败';
}

五、方案对比与选择建议

不同方案的适用场景和特点对比如下:

方案类型实时性服务端资源消耗实现难度适用场景
短轮询高(无效请求多)实时性要求低、并发小的场景
长轮询中等中等(保持连接)中等中等并发、实时性有一定要求的场景
WebSocket低(长连接复用)高(需要扩展支持)高并发、高实时性要求场景(聊天、实时监控等)
第三方服务低(无需自己维护服务)中小项目、快速上线需求、不想维护推送服务的场景

实际项目中可以根据业务需求、并发量、实时性要求选择合适的方案,也可以组合使用多种方案,比如非核心消息用短轮询,核心实时消息用WebSocket,进一步提升系统灵活性。

消息推送短轮询长轮询WebSocketWorkerman

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。