我试图在PHP后端使用SSE向用户发送消息。
后端代码的功能部分看起来像-
<?php
set_time_limit(0);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
ignore_user_abort(0);
@session_start();
ob_start();
echo "retry: 1000'n";
ob_flush();
flush();
require_once 'sql_connection_class.php';
require 'chatbox_class.php';
$chatbox=new chatboxclass($_GET['friendid']);
function recursivesenddata(){
global $chatbox;
$jsonobj=$chatbox->jsonloadunreadmessages();
//append json object
if($jsonobj!=-1){
> echo "data:{$jsonobj}'n'n";
> ob_flush();
> flush();
> }else{
> //don't send anything
> }
}
while(true){
recursivesenddata();
session_write_close();
sleep(1);
}
?>
当用户关闭页面时,ignoreuserabort(0)似乎什么都不做。
在$chatbox->jsonloadreadmessages()中,有一个函数应该只在页面打开时执行,它会更新mySQL数据库中的内容。但是即使页面关闭,这个脚本也会继续在服务器上运行!
当用户关闭页面以退出无限while循环时,是否在服务器端进行检查?
PHP脚本应该在连接套接字关闭后立即终止。如果用户关闭页面时脚本仍在运行,那么Apache/PHP配置就出现了严重问题。
当客户端明确调用EventSource.close()
、由于网络问题导致连接丢失、客户端关闭页面或PHP脚本终止时,可能会发生套接字关闭。
ignore_user_abort(false)
什么也不做;这是默认行为(脚本在连接关闭时终止)。将true
作为参数传递会使您的脚本在连接中幸存下来,但这并不能解决您的问题。
您的retry: 1000
没有任何作用,因为您从未关闭服务器端的套接字。当客户端激活EventSource
对象时,应该调用您的PHP脚本,并仅在客户端请求时终止(或者如果网络出现故障),因此无论最初的DB调整如何,每次聊天连接都应该只发生一次。这是假设客户端没有做任何会关闭连接的事情。
顺便说一句,这会给服务器带来很大的压力:在整个聊天过程中,每个聊天客户端都会运行一个PHP进程,而轮询周期大约小了10倍(10秒绰绰有余)。让客户端每隔30秒左右轮询一次新消息会减少浪费。
ignore_user_abort()在IIS系统上被忽略,您的配置可能会阻止它。
尝试在while循环中使用connection_aborted():
while ( connection_aborted() == 0 ) {
recursivesenddata();
session_write_close();
sleep(1);
}