我有一个 php 服务器文件和一个 HTML 客户端文件,HTML 文件每 500 ms
向服务器发送 ajax 请求以检索数据,尽管这按预期工作,但会导致内存使用率过高,并且客户端设备上的 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";
}
}
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);
我想找到一个 ajax 的替代解决方案,而不是向服务器发送大量请求并在大多数时间检索相同的数据,如果服务器可以在数据更改或更新时与客户端交互,效率会更高.
我无法使用 PHP Socket
或 HttpRequest
方法,因为它们没有安装在我的托管服务器上,我不确定后者是否有效。我能想到的唯一方法是使用 SESSIONS
。
根据 this PHP 服务器将所有用户 session 存储在服务器上的同一目录中,因此可以直接在文件上更改特定用户的 session 变量。然而,问题是这些文件中的数据是序列化的,我不确定如何反序列化数据并重新序列化它们,然后保存新数据!
即使我能够找到一种方法来存储 session 文件的更新,我仍然需要使用 setInterval 来监听 session 变量每 500ms
的变化,虽然这不是理想的但它会在内存和 CPU 使用率方面比使用 XMLHttpRequest
好得多。
那么最好的方法是什么?任何帮助将不胜感激。
更新:
我意识到 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);
}
}
}
它一直在继续,即使 logs.txt
大小增加它也不会中断!我怎样才能让它中断并回显大小增加的数据?
更新 2:
事实证明,php 在调用 filesize()
方法时会缓存文件大小,因此上述循环将无限期运行,解决方案是使用 clearstatcache()
方法这将清除存储的文件大小缓存,从而允许循环在文件大小更改时中断。
最佳答案
好吧,经过多次测试和长期研究,我得出结论,除非客户端先向服务器发送请求,否则 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);
}
以上代码将插入/更新数据,创建文件 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
}
}
}
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);
这不是理想的解决方案,但它将我的 xmlhttp 请求从 2/秒减少到 1/25 秒,希望有人能够提出更好的解决方案。
关于php - 从服务器向客户端发送数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16088691/