从服务器发送数据到客户端?

raz*_*zak 9 php ajax performance session

我有一个php服务器文件和一个HTML客户端文件,HTML文件向服务器发送ajax请求以检索每个数据500 ms,这虽然按预期工作,导致客户端设备上的内存和CPU使用率很高.

PHP

if(isset($_POST['id']) && $_POST['id'] != '' )
{
    $id     = $_POST['id'];
    $select = $con->prepare("SELECT * FROM data WHERE id=?");
    $select->bind_param('s', $id);
    $select->execute();
    $result = $select->get_result();
    while($row = $result->fetch_assoc())
    {
        echo $row['column 1'] . "\t" . $row['column 2'] . "\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

AJAX

function send(){
    var formdata = new FormData(),
        id       = document.getElementById('id').value;
    formdata.append('id', id);
    var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
    xhr.open('post', 'server.php', true);
    xhr.send(formdata);
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4 && xhr.status == 200){
            console.log(xhr.responseText);
        }
    }
}
setInterval(function(){send()}, 500); 
Run Code Online (Sandbox Code Playgroud)

我想找到ajax的替代解决方案,而不是向服务器发送大量请求并在大多数时间检索相同数据,如果服务器可以在数据更改或更新时与客户端进行交互,那么效率会更高.

我不能使用PHP SocketHttpRequest方法,因为它们没有安装在我的托管服务器上,我不确定后者是否有效.我能想到的唯一方法就是使用SESSIONS.

根据 PHP服务器将所有用户会话存储在服务器上的同一目录中,因此可以直接在文件上更改特定用户的会话变量.然而问题是这些文件中的数据是序列化的,我不知道如何反序列化数据并重新序列化它们然后保存新数据!

即使我能够找到一种方法来存储会话文件的更新,我仍然需要使用setInterval来监听会话的变量,500ms尽管它并不理想,但它比使用XMLHttpRequest内存和CPU使用情况要好得多.

那么最好的方法是什么?任何帮助将非常感激.


更新:

我意识到它SESSION不会工作,因为它只能由服务器而不是客户端读取,因此我必须向服务器发送ajax请求以获取我试图避免的变量.

我尝试了很长时间的轮询,但我遇到了很多问题,flush并且ob_flush()无法在我的服务器上运行,我也无法更改ini设置.在尝试无限循环时,我无法让它在数据更改时中断:

if(isset($_GET['size']) && $_GET['size'] != '')
{
    $size = (int)$_GET['size'];
    $txt = "logs/logs.txt";
    $newsize = (int)filesize($txt);    
    while(true) {
        if($newsize !== $size) {
            $data = array( "size" => filesize($txt), "content" => file_get_contents($txt));
            echo json_encode($data);
            break;
        }
        else{
            $newsize = (int)filesize($txt);
            usleep(400000);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

它一直在继续,即使logs.txt尺寸增加它也不会破裂!如何让它在大小增加时打破并回显数据?

更新2:

事实证明,当调用filesize()方法时,php缓存文件大小,因此上面的循环将无限期地运行,解决方案是使用clearstatcache()方法将清除存储的文件大小的缓存,允许循环中断文件大小的更改.

raz*_*zak 5

好的,经过多次测试和长时间的研究,我得出的结论是PHP服务器永远不能直接与指定的客户端交互,除非客户端首先向服务器发送请求.

我发现唯一可靠的解决方案是使用无限循环,这只会破坏数据更改,这将大大降低对服务器的ajax请求的频率,从而提高性能并降低客户端设备上内存和CPU的使用,它是怎么回事:

PHP 1(处理数据更新或新数据插入到数据库):

$process = $_POST['process'];
$log = "/logs/logs.txt";

if($process == 'update'){
    //execute mysqli update command and update table.
    $str = "Update on " . date('d/m/Y - H:i:s') . "\n";//add some text to the logs file (can be anything just to increase the logs.text size)
    file_put_content($log, $str, FILE_APPEND);//FILE_APPEND add string to the end of the file instead or replacing it's content
}
else if($process == 'insert'){
    //execute mysqli insert command and add new data to table.
    $str = "Added new data on" . date('d/m/Y - H:i:s') . "\n";
    file_put_content($log, $str, FILE_APPEND);
}
Run Code Online (Sandbox Code Playgroud)

上面的代码将插入/更新数据,log.txt如果不存在则创建文件,并在每个请求上添加其他文本.log.txt稍后将在"下面"的无限循环中使用,并在它的大小改变时打破循环.

PHP 2(处理读取数据请求):

if(isset($_POST['id']) && $_POST['id'] != '' && isset($_POST['size']) && $_POST['size'] != '')
{
    $id         = (string)$_POST['id'];
    $init_size  = (int)$_POST['count'];
    $size       = file_exists('logs/logs.txt') ? (int)filesize('logs/logs.txt') : 0;//$size is logs.txt size or 0 if logs.txt doesn't exist(not created yet).

    $select = $con->prepare("SELECT * FROM data WHERE id=?");
    $select->bind_param('s', $id);

    while(true){ //while(true) will loop indefinitely because condition true is always met
        if($init_size !== $size){
            $select->execute();
            $result = $select->get_result();
            while($row = $result->fetch_assoc())
            {
                $data['rows'][] = array(
                                  "column 1" => $row['column 1'],
                                  "column 2" => $row['column 2'],
                                  );

            }
            $data['size'] = $size;
            echo json_encode($data);
            break; //break the loop when condition ($init_size != $size) is met which indicates that database has been updated or new data has been added to it.
        }
        else{
            clearstatcache(); //clears the chached filesize of log.txt
            $size = file_exists('logs/logs.txt') ? (int)filesize('logs/logs.txt') : 0;
            usleep(100000) //sleep for 100 ms
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

AJAX:

var size = 0; //declares global variable size and set it's initial value to 0

function send(s){
    var formdata = new FormData(),
        id       = document.getElementById('id').value;
    formdata.append('id', id);
    formdata.append('size', s);
    var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
    xhr.open('post', 'server.php', true);
    xhr.timeout = 25000; //set timeout on xmlhttprequest to 25 sec, some servers has short execution tiemout, in my case it's 27 sec so i set the value to 25 sec.
    xhr.send(formdata);
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4 && xhr.status == 200){
            var data = JSON.parse(xhr.responseText);
            size = data.size;
            console.log(data.rows);
            setTimeout(function(){send(size)}, 100); //re-initiate the request after receiving data 
        }
    }
    xhr.ontimeout = function(){
        xhr.abort(); //abort the timed out xmlhttp request
        setTimeout(function(){send(size)}, 100);
}
send(size); 
Run Code Online (Sandbox Code Playgroud)

这不是理想的解决方案,但它将我的xmlhttp请求从2 /秒减少到1/25秒,希望有人能够提出更好的解决方案.

  • `PHP服务器永远不能直接与指定的客户端交互,除非客户端首先向服务器发送请求.这就是HTTP的工作原理https://developer.mozilla.org/en-US/docs/HTTP (4认同)
  • 服务器发送事件怎么样?查看有关 https://www.w3schools.com/html/html5_serversentevents.asp 的更多信息 (2认同)