2013-04-18 161 views
8

我有一個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"; 
    } 
} 

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 SocketHttpRequest方法,因爲它們沒有安裝在我的託管服務器上,我不確定後面的方法是否正常。我能想到的唯一方法是使用SESSIONS

根據this PHP服務器將所有用戶會話存儲在服務器上的同一目錄中,因此可能直接在文件上更改特定用戶的會話變量。但問題是這些文件中的數據是序列化的,我不確定如何反序列化數據並重新序列化它們,然後保存新數據!

即使我能找到一種方法來存儲會話文件的更新,我仍然需要用setInterval來聽會話的變量變化每500ms雖然它不是理想的,但它會比使用XMLHttpRequest好得多內存和CPU使用情況。

那麼最好的辦法是什麼?任何幫助將非常感激。


UPDATE:

我意識到SESSION不會工作,因爲它可以通過服務器而不是客戶端只讀的,所以我要送AJAX請求到服務器來獲取變量,我試圖避免。

我嘗試了很長時間的投票,但是我有很多問題,flushob_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:

它調用filesize()方法因此,上述循環將無限期地運行時原來PHP的高速緩存中的文件大小,對於該解決方案是使用clearstatcache()方法至極將清除的所存儲的高速緩存文件大小允許循環在文件大小更改上斷開。

+0

多久你希望你的響應數據的改變? –

+0

它有所不同,可能是每10秒一次或每10分鐘一次 – razzak

+0

結果集有多大?在kb? – hek2mgl

回答

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); 
} 

上面的代碼將插入/更新數據,如果不存在創建文件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/sec至低至1/25秒,希望有人能夠想出更好的解決方案。

+4

'PHP服務器不能直接與指定的客戶端進行交互,除非客戶端首先向服務器發送請求。「這就是HTTP的工作原理https://developer.mozilla.org/en-US/docs/HTTP – Ejaz

1

回答有關直接編輯會話的部分問題...

要直接操作用戶的會話,我會假設你知道並且可以跟蹤任何用戶的會話ID(可能在登錄時在你的數據庫中)。

當你需要在服務器上直接編輯用戶的會話:

  1. 從數據庫中檢索用戶的最後一個已知的會話。
  2. 致電session_close()關閉當前會話(如果有)。
  3. 使用會話ID調用`session_name($ sessionId)'。
  4. 致電session_open()開啓該會話。應使用會話數據填充$_SESSION。你不需要反序列化任何東西。
  5. 進行會話的編輯。
  6. 致電session_close()重新排列數據。

或者,你可以直接打開會話文件,unserialize()它,編輯數據,並手動重新serialize()

+0

謝謝,但我意識到'session'不會工作,因爲它只能通過服務器而不是客戶端讀取,所以我必須發送'xmlhttprequest'到服務器並回到原來的一個。 – razzak

1

您可以創建一個PHP腳本的ajax請求,只有在有新數據時纔會返回數據。只要沒有新的數據,腳本就會一直運行,直到出現爲止。

4

在我們有能力在瀏覽器中使用套接字之前,我們使用了長輪詢。基本思想是,瀏覽器不是定期向瀏覽器發出請求,而是向服務器發出請求,但服務器不會響應,直到有什麼值得分享給瀏覽器爲止。這意味着請求可以保持開放10ms或幾個小時。

服務器響應某些內容後,瀏覽器的工作就是創建新的ajax請求。這樣,總是有一條線對服務器開放。

有關更多信息,請參閱this question

0

我認爲今天這個問題的答案是使用Websocket閱讀有關它。不要求你能得到的數據,如果有什麼東西把它變成服務器的服務器

link

相關問題