Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending data from server to client?

I have a php server file and an HTML client file, the HTML file send ajax requests to the server to retrieve data every 500 ms, this although works as expected it's causing high usage of memory and CPU on the client's device.

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

I would like to find an alternative solution to ajax, instead of sending numerous requests to the server and retrieving same data most of the time, it would be much more efficient if the server can interact with the client on data change or update.

I can't use PHP Socket or HttpRequest methods as they are not installed on my hosting server and I'm not sure if the later works. The only way I can think of is using SESSIONS.

According to this PHP server store all users sessions on the same directory on the server, therefore it may be possible to change sessions variables for a particular user directly on the file. The problem however is the data in those files are serialized and I'm not sure how to de-serialize the data and re-serialize them and then save the new data!

Even if I was able to find a way to store updates on the session file, I still need to use setInterval to listen to the session's variable change every 500ms although it's not ideal but it would be much better than using XMLHttpRequest in terms of memory and CPU usage.

So what's the best way to do this? any help would be much appreciated.


UPDATE:

I realized that SESSION wont work because it can be read only by the server not the client, therefore i have to send ajax request to the server to get the variables which i was trying to avoid.

I tried long polling but i had many problems with it, flush and ob_flush() doesn't work on my server and i can't change the ini settings. When trying the infinite loop i can't get it to break on data change:

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

it keeps going on and on, even if the logs.txt size increase it won't break! how can I make it break and echo data on size increase?

UPDATE 2:

It turned out the php cache the filesize when calling filesize() method therefore the above loop will run indefinitely, the solution for that is to use clearstatcache() method which will clear the stored cache of the file size allowing the loop to break on filesize changes.

like image 897
razz Avatar asked Apr 18 '13 16:04

razz


People also ask

Can server send data to client?

Data passes back and forth between the client and server, and scripts can run on both sides.

How send data from server to client without request?

You can use web-sockets which are two way communication between client and server that remain open and allow the server to send without request from the client. However web-sockets are new and browser support is only for the most current browsers.

In which form the server sends the data to the client?

Sending the form data using the 'POST' HTTP method: The POST method is used to send data to a server to create and update a resource. The requested data using the POST method is appended to the body of the HTTP request rather than the page URL.

How do I send data from server to client in node?

Methods to send response from server to client are:Using send() function. Using json() function.


2 Answers

Okay, after many tests and long research i came to the conclusion that PHP server can never interact with a specified client directly unless the client send a request to the server first.

The only reliable solution i found is to use infinite loop which will only break on data change, this will reduce the frequency of ajax requests to the server considerably, hence increasing the performance and decreasing the usage of the Memory and CPU on the client's device, here how it goes:

PHP 1 (Handles data update or new data insert to database):

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

The above code will insert/update data, create file log.txt if not existed and add additional text to it on each request. log.txt will be used later in the infinite loop "below" and would break the loop when it's size change.

PHP 2 (handles reading data requests):

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

This is not the ideal solution but it reduced my xmlhttp requests from 2/sec to as low as 1/25 sec, hope that someone will be able to come up with a better solution.

like image 170
razz Avatar answered Oct 20 '22 20:10

razz


Before we had capabilities to use sockets in browsers, we used Long polling. The basic idea is that instead of the browser making requests at regular intervals, the browser will make a request to the server, but the server won't respond until there is something worthwhile to share back to the browser. That means the request could be left open for 10ms or for hours.

After the server responds with something, it is then the browser's job to make a new ajax request. This way, there is always a line open to the server.

Refer to this question for more information.

like image 24
matthewmatician Avatar answered Oct 20 '22 19:10

matthewmatician