PHPWebSocket与实时通信技术
PHP WebSocket与实时通信技术传统的HTTP请求是单向的客户端发起请求服务器返回响应。实时通信需要服务器主动推送数据给客户端。PHP有几种方式实现实时通信从简单的轮询到WebSocket都能做。最简单的实时通信方式是短轮询。客户端定时发送请求检查是否有新数据。php// 短轮询服务端function pollForUpdates(int $userId, int $lastId 0): array{$pdo new PDO(mysql:hostlocalhost;dbnametest, root, );$stmt $pdo-prepare(SELECT * FROM notificationsWHERE user_id ? AND id ?ORDER BY id DESCLIMIT 10);$stmt-execute([$userId, $lastId]);return $stmt-fetchAll();}// 长轮询服务端保持连接直到有新数据function longPollForUpdates(int $userId, int $lastId 0, int $timeout 30): array{$start time();$pdo new PDO(mysql:hostlocalhost;dbnametest, root, );while (time() - $start $timeout) {$stmt $pdo-prepare(SELECT * FROM notificationsWHERE user_id ? AND id ?ORDER BY id DESCLIMIT 10);$stmt-execute([$userId, $lastId]);$notifications $stmt-fetchAll();if (!empty($notifications)) {return [data $notifications, type new_data];}// 检查是否有超时请求if (connection_aborted()) break;sleep(2); // 2秒后重试}return [data [], type timeout];}header(Content-Type: application/json);header(Cache-Control: no-cache);$result longPollForUpdates(1, 0);echo json_encode($result);?用Swoole实现WebSocket服务器php// Swoole WebSocket服务器use Swoole\Http\Request;use Swoole\Http\Response;use Swoole\WebSocket\Server;use Swoole\WebSocket\Frame;$server new Server(0.0.0.0, 9502);// 存储在线用户$onlineUsers new Swoole\Table(1024);$onlineUsers-column(user_id, Swoole\Table::TYPE_INT);$onlineUsers-column(name, Swoole\Table::TYPE_STRING, 50);$onlineUsers-create();$server-on(start, function (Server $server) {echo WebSocket服务器已启动 on 0.0.0.0:9502\n;});$server-on(open, function (Server $server, Request $request) {$fd $request-fd;echo 新连接: #{$fd}\n;// 发送欢迎消息$server-push($fd, json_encode([type welcome,message 连接成功,fd $fd,]));});$server-on(message, function (Server $server, Frame $frame) {$fd $frame-fd;$data json_decode($frame-data, true);if (!$data) return;switch ($data[type] ?? ) {case login:// 用户登录$onlineUsers-set((string)$fd, [user_id $data[user_id],name $data[name],]);// 广播上线通知$server-push($fd, json_encode([type login_success,message 登录成功,]));broadcastUserList($server);break;case message:// 群发消息$user $onlineUsers-get((string)$fd);$msg [type message,from $user[name] ?? 匿名,content $data[content],time date(H:i:s),];foreach ($server-connections as $clientFd) {if ($server-isEstablished($clientFd)) {$server-push($clientFd, json_encode($msg));}}break;case private:// 私信$user $onlineUsers-get((string)$fd);$targetFd $data[to_fd];if ($server-isEstablished($targetFd)) {$server-push($targetFd, json_encode([type private,from $user[name] ?? 匿名,content $data[content],time date(H:i:s),]));}break;case ping:$server-push($fd, json_encode([type pong]));break;}});$server-on(close, function (Server $server, int $fd) {$user $onlineUsers-get((string)$fd);if ($user) {$onlineUsers-del((string)$fd);broadcastUserList($server);}echo 连接关闭: #{$fd}\n;});function broadcastUserList(Server $server): void{global $onlineUsers;$users [];foreach ($onlineUsers as $fd $user) {$users[] [fd (int)$fd,user_id $user[user_id],name $user[name],];}$msg json_encode([type user_list, users $users]);foreach ($server-connections as $fd) {if ($server-isEstablished($fd)) {$server-push($fd, $msg);}}}$server-start();?WebSocket客户端连接代码php// WebSocket客户端JavaScript?// Server-Sent Events (SSE) 替代方案header(Content-Type: text/event-stream);header(Cache-Control: no-cache);header(Connection: keep-alive);while (true) {$data [time date(Y-m-d H:i:s), message 心跳];echo data: . json_encode($data) . \n\n;ob_flush();flush();if (connection_aborted()) break;sleep(5);}?SSE的客户端使用方式php// SSE客户端JavaScript??实时通信的方案选择取决于具体需求。简单的通知推送用SSE就够了双向通信需求用WebSocket。Swoole让PHP具备了实现WebSocket的能力但在高并发场景下专门的实时通信服务如Pusher、Firebase也是值得考虑的方案。