ajax chat belastend voor de server?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Niels Vanderheyden

Niels Vanderheyden

25/03/2011 11:25:58
Quote Anchor link
Hallo

Ik ben bezig aan een simpele ajax chat en er kunnen zelfs images verstuurd worden.
Maar ik vraag me nu af is zo een ajax chat niet vrij belastend voor de server omdat er elke seconde data wordt opgehaald?
Mijn chat werkt dus via een timer.

Stel dat ik dit had gemaakt met php sockets was dit dan minder zwaar voor de server?

Alvast bedankt.
 
PHP hulp

PHP hulp

20/04/2024 07:37:11
 
Gerben Jacobs

Gerben Jacobs

25/03/2011 12:34:45
Quote Anchor link
Bij sockets staan de connecties constant open, lijkt mij dat dat meer kost.
Ajax chats zijn meestal niet extreem server-belastend, maar als die plaatjes op jouw server staan, zou ik wel zorgen dat je ze goed cached.

Ben echter geen expert op dat gebied, dus ben ik benieuwd naar verdere reacties.
 
Niels Vanderheyden

Niels Vanderheyden

28/05/2011 22:21:59
Quote Anchor link
Iemand anders hier ervaring mee?
 
Jelmer -

Jelmer -

29/05/2011 00:24:57
Quote Anchor link
Het ligt er heel erg San hoe je het maakt. Als je iedere seconde een reageer doet naar een PHP script, dat door Apache verwerkt moet worden dan is dat aardig belastend. Stel dat je server apache met PHP als cgi module gebruikt, dan kan je met een behoorlijke server niet meer dan ong. 20 mensen aan.

Maar als je apache hierin vervangt door iets dat niet constant PHP hoeft te initialiseren en de berichten en het script gewoon in het geheugen houdt, kom je al een stuk verder. Ik denk dat je al aardig wat requests per seconde kan afvangen met een servertje geschreven in node.js.

Als je dan toch al die kant op gaat, kan je ook de verbindingen open houden. Open verbindingen zelf kosten niet zoveel, een verbinding opbouwen is een stuk intensiever. Naja, niet in het geval van apache omdat die een hele PHP omgeving per verbinding in het geheugen houdt, maar met bode.js kost het maar een paar bytes per verbinding. Dan zou je long-pooling kunnen doen: je doet een requests voor nieuwe berichten naar je server, en je server geeft pas antwoord wanneer er nieuwe berichten zijn.
 
Xaboteur X

Xaboteur X

08/03/2012 13:45:16
Quote Anchor link
Jelmer, zou je misschien een klein voorbeeld kunnen geven van dat laatste?

Ik zit namelijk met hetzelfde probleem als OP, met een timer, die om de seconde mijn logfile opnieuw ophaald met Ajax.
Hierdoor wordt de inhoud van de chat om de seconde opnieuw geladen, en kan ik bijvoorbeeld niet op mijn gemak inhoud selecteren, zoals links en dergelijke. Zeer ambetant.

Zijn er nog andere oplossingen voor deze situatie misschien?
 
Kris Peeters

Kris Peeters

08/03/2012 18:34:36
Quote Anchor link
Xaboteur X op 08/03/2012 13:45:16:
Jelmer, zou je misschien een klein voorbeeld kunnen geven van dat laatste?


Jelmer, indien je dit ziet, antwoord dan zelf maar he ..

Ik denk dat dit zo ongeveer de bedoeling is.
Even het Ajax deel tonen.

Dus ... om de seconde kijk je naar de server; je ziet of de laatste id op de server overeenkomt met die waarde die je zelf in javascript opslaat.

Zolang de id's overeenkomen, is er geen nieuwe post.
In het andere geval zijn er wel nieuwe posts
Zoek dan die posts op en verander je de update de laatste id in javascript.

Dat geeft zoiets: (code zegt meer dan 1000 woorden ...)

index.php
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<html>
  <head>
    <link rel="stylesheet" type="text/css" href="style.css"/>
  </head>
  <body>
    <div id="posts">
      posts komen hier
    </div>
    <script src=" https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script src="js.js"></script>
  </body>
</html>


js.js
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
(function() {
  // settings
  var interval = 1000;
  var posts = $('#posts');
  // hou het laatste id bij.  Om de zoveel tijd gaan we controleren of dit id nog overeen komt met de laatste id op de server
  var lastId = 0;
  getLastId();
  /**
  *  deze functie doet maar 1 ding: het stuurt een Ajax request naar de server met als GET variabele: var lastId
  */
  function getLastId() { //
    $.ajax ({
      url: 'posts.php?action=lastid&id=' + lastId,
      success: function(data) {
        // data is een bericht van de server; antwoord van het Ajax request.
        // data is de last id die op de server gevonden wordt.
        data = Number(data);
        if (data !== NaN && Number(data) == lastId) {
          setTimeout(getLastId, interval);  // Geen nieuw id gevonden.  Een seconde later nog eens proberen
        }
        else {
          // er is een verschil tussen de id op de server en die bij de client
          // nu gaan we de data volledig halen.
          // We sturen de last id van bij de client toch op naar de server.  Eventueel haal je enkel de nieuwe posts op (alle posts met id > lastId)
          $.ajax({
            url: 'posts.php?action=posts&id=' + lastId,
            success: function(data) {
              // data is hier de posts; volledig, in HTML formaat
              // we steken die in de juiste div
              posts.html(data);
              // en uiteraard opnieuw de message loop op gang trekken
              setTimeout(getLastId, interval);
            }
          });
          // we zetten op deze plaats de id lokaal op de nieuwe waarde.
          lastId = data;
        }
      }  // / success
    });
  }
})();


posts.php
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
  switch(isset($_GET['action']) ? $_GET['action'] : '') {
    case
'lastid':
      
      $id = 24;  // dummy waarde; je haalt dit uit de DB
      
      // "SELECT id FROM my_table ORDER BY id DESC LIMIT 1" ...

      echo $id;
      break;
    case
'posts':
    
      echo $allPosts = ' bla bla bla ' . time();  // posts ophalen uit data.
      break;
  }

?>


Als je posts.php aanpast, werkt deze code.
Ondertussen kan je al eens controleren met de dummy-waarden:

Terwijl een venster open staat:
- verander $allPosts ( val bla bla naar iets anders ) en sla posts.php op;
Er gebeurt niets.

- verander nu $id, van 24 naar iets anders.
Binnen de seconde wordt dit gedetecteerd en en wordt een verzoek gedaan om de nieuwe posts (nu dus in $allPosts) te halen.


Dit is dus nog heel ruw; er is nog een hoop dat beter kan.
(PS: nu ik dit lees ... de naam en commentaar van/bij getLastId is nogal ongelukkig, als je met anonieme functies werkt ...)
Gewijzigd op 08/03/2012 18:50:14 door Kris Peeters
 
Xaboteur X

Xaboteur X

08/03/2012 19:35:26
Quote Anchor link
Hmm, Kris, dat is al een mooi voorbeeld!
Ik ga het zelf eens onder de loep nemen.
Maar is het ook mogelijk om nog steeds met een logfile te werken? (En bijvoorbeeld steeds de id vanvoor te zetten ofzo?)

Alvast bedankt!
 
Niels K

Niels K

08/03/2012 19:43:56
Quote Anchor link
Beste Xaboteur,

Heb je wel eens gekeken naar de 'Ajax Push Engine?'.

Mvg,

Niels
 
Kris Peeters

Kris Peeters

08/03/2012 20:23:18
Quote Anchor link
Misschien kan je wel via een file werken.

Enkel al een heel kleine file enkel met de laatste id; misschien kan dat al veel helpen.

Bij de insert:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php

...
$lid= mysql_insert_id($con);
file_put_contents('lid.txt', $lid);
...

?>


en dan roep je als eerste ajax request:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
...
   url: 'lid.txt',
...


Kan je eens proberen
Gewijzigd op 08/03/2012 20:24:33 door Kris Peeters
 
Xaboteur X

Xaboteur X

09/03/2012 13:43:43
Quote Anchor link
Niels, gisteren ook nog bij APE uitgekomen, ga ik zeker naar kijken!

Kris, het id-gebeuren moet dus altijd met een database werken?
 
Kris Peeters

Kris Peeters

09/03/2012 15:19:32
Quote Anchor link
Bij elke nieuwe post sla je de laatste id op in een tekstfile. Het lezen van die id kan dus verder gebeuren via die tekstfile. Lezen van een tekstfile belast apache niet en er zijn geen DB connecties.
 
Kris Peeters

Kris Peeters

12/03/2012 00:40:17
Quote Anchor link
Ik heb het wat uitgewerkt.

Er is nog werk aan, maar je hebt een werkende basis.
Dus, het lezen van de laatste id gebeurt via een file

(zie dat de rechten in orde zijn zodat apache een file kan lezen en schrijven; eventueel zet je de file "lid.txt" zelf in de map)


Als iemand goesting heeft om dit echt uit te testen online ... laat weten of dit echt werkt

index.php
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
session_start();
if(isset($_SESSION['login'])) {
    $form = '
        <h3>NICK NAME: '
. htmlentities($_SESSION['login']['login']) . '</h3>
        <a href="posts.php?action=logout">Log out</a>
      <form class="chat" action="" method="post">
        <ul>
          <li><input class="message" name="message"/></li>
          <li><input class="button" type="submit" '
. ( isset($_SESSION['login']) ? '' : ' disabled="disabled" ' ) . 'value="CHAT"/></li>
        </ul>
      </form>
      '
;
}

else {
    $form = '
      <form action="posts.php?action=login" method="post">
        <ul>
          <li><input name="login"/> NICK NAME </li>
          <li><input class="button" type="submit" value="Login"/></li>
        </ul>
      </form>
      '
;
}

?>

<html>
  <head>
    <link rel="stylesheet" type="text/css" href="style.css"/>
  </head>
  <body>
    <div id="posts">
      posts komen hier
    </div>
    <div id="form_container">
      <?php echo $form;  ?>
    </div>
    <script src=" https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script src="js.js"></script>
  </body>
</html>


posts.php
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php
session_start();
/*
CREATE TABLE IF NOT EXISTS chat (
  id int(11) NOT NULL AUTO_INCREMENT,
  message varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  nick varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2 ;

INSERT INTO chat (id, message, nick, created) VALUES
(1, 'My first message', 'Kris', CURRENT_TIMESTAMP);
*/


    $con = mysql_connect('localhost', 'root', '');
    mysql_select_db('phphulp', $con);

if($_SERVER['REQUEST_METHOD'] === 'POST') {
        
    switch(isset($_GET['action']) ? $_GET['action'] : '') {
      case
'login':
        if (isset($_POST['login'])) {
          // array met gegevens over de client.  Doe hier eventueel meer mee ...
          $_SESSION['login'] = array(
            'login' => $_POST['login'],
            'time' => time(),
            'ip' => $_SERVER['REMOTE_ADDR']
          );
        }

        header('location: index.php');
        break;
      case
'insert':
        if (isset($_POST['message'])) {
          $res = mysql_query(sprintf(
            "INSERT INTO chat (message, nick, created) VALUES ('%s', '%s', CURRENT_TIMESTAMP);",
            mysql_real_escape_string($_POST['message']),
            mysql_real_escape_string($_SESSION['login']['login'])
          ));

          $lid= mysql_insert_id($con);
          file_put_contents('lid.txt', $lid);
          echo 1;
        }

        break;
    }
}

else {
    switch(isset($_GET['action']) ? $_GET['action'] : '') {
      case
'posts':
          $res = mysql_query("SELECT id, message, nick, created FROM chat ORDER BY created DESC" );
          while($row = mysql_fetch_assoc($res)) {
            echo '<div class="post">
              <div class="message">'
. htmlentities($row['message']) . '</div>
              <span class="nick">'
. htmlentities($row['nick']) . '</span>
              <span class="created">'
. htmlentities($row['created']) . '</span>
            </div>'
;
          }


        break;
      case
'logout':
        unset($_SESSION['login']);
        header('location: index.php');
        break;
    }
}

?>


js.js
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
(function() {
  // settings
  var interval = 1000;
  var posts = $('#posts');
  var dt = new Date( );
  
  // var loginForm = $('form.login');
  // var chatForm = $('form.chat');
 
  // hou het laatste id bij.  Om de zoveel tijd gaan we controleren of dit id nog overeen komt met de laatste id op de server
  var lastId = 0;
  bindEvents();
  getLastId();
  
  // bind events
  
  function bindEvents() {
   $('form.chat').submit(function(e) {
      e.preventDefault();
      $.ajax({
        url: 'posts.php?action=insert',
        type: 'post',
        data: $(this).serialize(),
        success: function(data) {
        }
      });
      setTimeout(blurred, 300);
    });
  }
  function blurred() {
    $('form.chat').find('input.message').val('');
  }
  
  /**
  *  deze functie doet maar 1 ding: het stuurt een Ajax request naar de server met als GET variabele: var lastId
  */
  function getLastId() { //
    $.ajax ({
      url: 'lid.txt?t=' + dt.getTime().toString(),  // om extra zeker te zijn dat de file wordt gelezen, en niet zomaar de cache, veranderen we telkens de url, met een dummy waarde, bv. de tijd
      cache: false,
      success: lastIdResponse   // / success
    });
  }
  /**
  *  De laatste id is van de server gehaald.  Indien die niet overeenkomt met de waarde lokaal halen we de berichten op.
  */
  function lastIdResponse(data) {
    // data is een bericht van de server; antwoord van het Ajax request.
    // data is de last id die op de server gevonden wordt.
    data = Number(data);
    if (data !== NaN && Number(data) == lastId) {
      setTimeout(getLastId, interval);  // Geen nieuw id gevonden.  Een seconde later nog eens proberen
    }
    else {
      // er is een verschil tussen de id op de server en die bij de client
      // nu gaan we de data volledig halen.
      // We sturen de last id van bij de client toch op naar de server.  Eventueel haal je enkel de nieuwe posts op (alle posts met id > lastId)
      $.ajax({
        url: 'posts.php?action=posts&id=' + lastId,
        success: dataResponse
      });
      // we zetten op deze plaats de id lokaal op de nieuwe waarde.
      lastId = data;
    }
  }  
  /**
  *  De posts zijn in opgehaald
  */
  function dataResponse(data) {
    // data is hier de posts; volledig, in HTML formaat
    // we steken die in de juiste div
    posts.html(data);
    // en uiteraard opnieuw de message loop op gang trekken
    setTimeout(getLastId, interval);
  }
})();


style.css
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#posts {
  width: 300px;
  height: 300px;
  overflow: auto;
  border: 1px solid #000;
}
li {
  list-style: none;
}

#posts .post {
  border-bottom: 1px dashed #999999;
}

#posts .nick {
  
}

#posts .created {
  color: #777777;
}
Gewijzigd op 12/03/2012 00:42:27 door Kris Peeters
 
Xaboteur X

Xaboteur X

12/03/2012 18:39:36
Quote Anchor link
Hey Kris,

Ik heb je voorbeeld getest en het lijkt inderdaad te werken! Super!
Moet het alleen nog beetje aanpassen en integreren in mijn systeempje.
Ik hou je nog op de hoogte.

Bedankt!

UPDATE: Kris, ik heb het ondertussen geïntegreerd, en mijn voormalig probleem is nu dus opgelost! Niet meer steeds die inhoud refresh, alleen als er iets gepost wordt! Super bedankt!
Gewijzigd op 12/03/2012 21:41:00 door Xaboteur X
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.