Long polling per verificare utenti on line
- Questo topic ha 8 risposte, 2 partecipanti ed è stato aggiornato l'ultima volta 9 anni, 2 mesi fa da jqueryitalia.
- AutorePost
- 2 Febbraio 2015 alle 16:30 #6584altieriPartecipante
Salve a tutti. Sono veramente disperato. Sono 4 giorni che ci sbatto la testa ma non riesco a venirne a capo.
Questo lo script lato client:
jQuery( function(){ if(jQuery.cookie('enable-chat')) { function user_longpolling(){ var t; jQuery.ajax({ url: 'php/chat/stream_users.php', type: 'GET', dataType: 'json', success: function( payload ){ clearInterval( t ); if( payload.status == 'results' || payload.status == 'no-results' ){ t=setTimeout( function(){ user_longpolling(); }, 1000 ); if( payload.status == 'results' ){ jQuery.each( payload.data, function(i,msg){ //jQuery( '.onlineusers ul li#u-'+ msg.id_user +'' ).removeClass('on'); jQuery( 'li#u-'+ msg.id_user +'').addClass(msg.stato); }); } } else if( payload.status == 'error' ){ alert('Sono confuso, cortesemente ricarica la pagina!'); } }, error: function(){ clearInterval( t ); t=setTimeout( function(){ user_longpolling(); }, 15000 ); } }); } user_longpolling(); } });
e questo lato server:
<?php require_once('global.php'); require_once('../functions.php'); sec_session_start(); $id_user = $_SESSION['user_id']; // crea connessione $conn = mysqli_connect($hostname_alliance, $username_alliance, $password_alliance, $database_alliance); // verifica connessione if (!$conn) { die("Connection failed: " . mysqli_connect_error()); } $time_wasted = 0; //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX //verifico se l'utente è già nella tabella $sql = "SELECT * FROM users_online where userid = ".$id_user.""; $result = $conn->query($sql); //se è stato già inserito aggiorno l'ora $time = time()+30; if ($result->num_rows > 0) { $sql = "UPDATE users_online SET timestamp = ".$time." WHERE userid = ".$id_user.""; }else{ //altrimenti lo inserisco nella tabella ed inserisco l'ora $sql = "INSERT INTO users_online (userid, timestamp) VALUES (".$id_user.", ".$time.")"; } //eseguo la query $conn->query($sql); //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $old_users_check = mysql_query("SELECT * FROM users_online WHERE timestamp < ".time()." AND stato = 'on' AND userid <> ".$id_user." ORDER BY userid DESC"); $new_users_check = mysql_query("SELECT * FROM users_online WHERE timestamp >= ".time()." AND stato = 'off' AND userid <> ".$id_user." ORDER BY userid DESC"); $num_rows_old = mysql_num_rows( $old_users_check ); $num_rows = mysql_num_rows( $new_users_check ); //se la prima query non mi da risultati if( $num_rows <= 0 && $num_rows_old <= 0 ){ //inizio il ciclo se non ottengo risultati while( $num_rows <= 0 && $num_rows_old <= 0 ){ if( $num_rows <= 0 && $num_rows_old <= 0 ){ // dopo 19 secondi invio una nuova richiesta if( $time_wasted >= 29 ){ die( json_encode( array( 'status' => 'no-results' ) ) ); exit; } sleep( 1 ); $old_users_check = mysql_query("SELECT * FROM users_online WHERE timestamp < ".time()." AND stato = 'on' AND userid <> ".$id_user." ORDER BY userid DESC"); $new_users_check = mysql_query("SELECT * FROM users_online WHERE timestamp >= ".time()." AND stato = 'off' AND userid <> ".$id_user." ORDER BY userid DESC"); $num_rows_old = mysql_num_rows( $old_users_check ); $num_rows = mysql_num_rows( $new_users_check ); $time_wasted += 1; } } } $new_user = array(); if( $num_rows_old >= 1): while ( $row = mysql_fetch_array( $old_users_check, MYSQL_ASSOC ) ): $new_user[] = array( 'id_user' => $row['userid'], 'stato' => $row['stato'] ); endwhile; mysql_query("UPDATE users_online SET stato = 'off ' WHERE timestamp < ".time()." AND stato = 'on' AND userid <> ".$id_user.""); endif; if( $num_rows >= 1): while ( $row = mysql_fetch_array( $new_users_check, MYSQL_ASSOC ) ): $new_user[] = array( 'id_user' => $row['userid'], 'stato' => $row['stato'] ); endwhile; mysql_query("UPDATE users_online SET stato = 'on ' WHERE timestamp >= ".time()." AND stato = 'off' AND userid <> ".$id_user.""); endif; mysql_free_result($old_users_check); mysql_free_result($new_users_check); die( json_encode( array( 'status' => 'results', 'data' => $new_user ) ) );
Le conseguenze sono drastiche. In effetti, verificando da console, alla prima richiesta inviata dal client, tutto procede regolarmente, ma appena parte la seconda chiamata, non mi permette più di interagire con il server fino all’ottenimento di una risposta. In sostanza, se invio un nuovo messaggio, rimane in sospeso finchè stream_users.php non esce dal ciclo. Non so se l’errore è causato dal client o dal server. Confido nel vostro aiuto
3 Febbraio 2015 alle 14:11 #6586jqueryitaliaAmministratoreCiao Franco!
Innanzitutto ti chiederei di fare attenzione quando inserisci codice nei post.
Ho provveduto io a sistemarlo questa volta 😉Per quanto riguarda la tua richiesta invece mi servirebbe sapere per prima cosa che versione di jQuery stai utilizzando.
Il problema credo sia comunque lato client e precisamente dovuto al fatto che esegui una ricorsione all’interno del primo ciclo if della success dove richiami di nuvo la funzione.4 Febbraio 2015 alle 12:31 #6591altieriPartecipanteciao e scusami per l’errore di inserimento.
La versione di jQuery che utilizzo è :
<script src="js/jquery-1.10.2.min.js"></script> <script src="js/jquery-migrate-1.2.1.min.js"></script>
Per quanto riguarda la ricorsione è intenzionale. Ti spiego la logica adottata:
Faccio partire la richiesta ajax al server.
il server esegue le 2 query iniziali. Se non trova records, inizia il ciclo while ripetendo le query ad un intervallo di 1 secondo. Il ciclo si dovrebbe fermare al 29esimo secondo ($time_wasted ) se non trova risultati. Se invece trova risultati esce dal ciclo e risponde con una array json.
Dopo 29 secondi, se non trova risultati, o prima se li trova, fa partire una nuova richiesta da ajax ed il gioco riprende (long polling). In questo modo, ogni mezzo minuto il client fa una richiesta al server e resta in ascolto.
Stò cercando di riprodurre una sorta di bacheca stile facebook. Questa tecnica la utilizzo per leggere i post e le rispote, con delle ovvie modifiche, e funziona alla perfezione.
Il problema sorge con la seconda richiesta di utenti on line di ajax. In effetti accade questo. Trascorsi i primi 29 secondi, entro i quali non mi sembra ci siano anomalie, se provo ad inviare un post o una risposta, l’invio mi rimane in sospeso fino a quando stream_users.php termina il ciclo. Questa cosa mi stà facendo veramente impazzire. Io credo fortemente che il problema sia lato server ma non riesco ad immaginare una strada diversa….4 Febbraio 2015 alle 12:41 #6594altieriPartecipanteFUORI ARGOMENTO.
Non riesco a capire come inserire correttamente il codice nel forum :p
5 Febbraio 2015 alle 13:53 #6595jqueryitaliaAmministratoreUn paio di cosuccie che ho notato guradando il codice php:
- nel primo ciclo while, questo per intenderci;
if( $num_rows <= 0 && $num_rows_old <= 0 ){ //inizio il ciclo se non ottengo risultati while( $num_rows <= 0 && $num_rows_old <= 0 ){ if( $num_rows <= 0 && $num_rows_old <= 0 ){ // dopo 19 secondi invio una nuova richiesta if( $time_wasted >= 29 ) { die( json_encode( array( 'status' => 'no-results' ) ) ); exit; } sleep( 1 ); $old_users_check = mysql_query("SELECT * FROM users_online WHERE timestamp < ".time()." AND stato = 'on' AND userid <> ".$id_user." ORDER BY userid DESC"); $new_users_check = mysql_query("SELECT * FROM users_online WHERE timestamp >= ".time()." AND stato = 'off' AND userid <> ".$id_user." ORDER BY userid DESC"); $num_rows_old = mysql_num_rows( $old_users_check ); $num_rows = mysql_num_rows( $new_users_check ); $time_wasted += 1; } } }
ci sono un po di cose strane…
Dentro al ciclo esegui un if( $num_rows <= 0 && $num_rows_old <= 0 ) che è lo stesso identico if che ti permette di entrare nel ciclo while. Quindi quell’if è inutile.
Non capisco inoltre il motivo per cui esegui uno sleep di 1 secondo… - Alla fine per restituire il valore json esegui un die(…) o_O
E questo probabilmente ti provoca tutti i problemi…
La chiamata ajax si aspetta un dato in json, ma non lo puoi restituire con un die!!!
Quindi fai così:<?php ob_start() require_once('global.php'); require_once('../functions.php'); sec_session_start(); ... ... ... /* IL RESTO DELLO SCRIPT PHP */ ... ... ob_end_clean(); echo json_encode( array( 'status' => 'results', 'data' => $new_user ) ); die();
Ovviamente dovrai eliminare anche il die con cui passi il no-results, facendo così:
ob_start_end(); echo json_encode( array( 'status' => 'no-results' ) ); die();
- Ti consiglio di restituire un json anche in caso di problemi di connessione, gestendo l’errore lato client. Quindi:
if (!$conn) { ob_end_clean(); echo json_encode( array( 'status' => 'no-connection' ) ); die(); }
Fammi sapere 😉
P.S.: prova a dare un’occhiata a questo tutorial http://tutorialzine.com/2010/03/who-is-online-widget-php-mysql-jquery/
5 Febbraio 2015 alle 19:11 #6596altieriPartecipante…non va. Io mi stò concentrando sulle chiamate ajax ma evidentemente l’errore non è da ricercarsi lì. Ho apportato le modifiche che mi suggerivi ma il problema rimane. Sono rimasto completamente impantanato. Veramente non riesco a capire. Ho tralasciato intenzionalmente la questione degli utenti on line e mi sono concentrato sulla chat. rifacendo esattamente ciò che ho fatto con i messaggi in bacheca, mi accade la stessa cosa. Quando invio un nuovo messaggio me lo lascia pendente finche non finisce il loop sul server. Questa cosa mi stà facendo impazzire…
5 Febbraio 2015 alle 19:20 #6597altieriPartecipantedimenticavo. Per i messaggi in bacheca utilizzo comunque die( json_encode( array(… e funziona bene… in ogni caso ora vado ad applicare il tuo suggerimento anche sulle pagine funzionanti. Mi affido completamente alla tua scienza
6 Febbraio 2015 alle 19:46 #6598altieriPartecipanteHo finalmente risolto.
L’errore era causato da sec_session_star();
La funzione la chiamavo già dal client e, quando veniva richiamata dal server mi mandava tutto in tilt.
Ci sono arrivato in modo deltutto casuale ma sono veramente felice di aver risolto ed aver avuto la tua attenzione.Grazie ancora.
6 Febbraio 2015 alle 22:09 #6600jqueryitaliaAmministratoreFelice per te 😉
- nel primo ciclo while, questo per intenderci;
- AutorePost
- Devi essere connesso per rispondere a questo topic.