ajax chat belastend voor de server?
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.
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.
Iemand anders hier ervaring mee?
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.
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?
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)
1
2
3
4
5
6
7
8
9
10
11
12
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>
<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)
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
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
});
}
})();
// 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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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!
Enkel al een heel kleine file enkel met de laatste id; misschien kan dat al veel helpen.
Bij de insert:
en dan roep je als eerste ajax request:
Kan je eens proberen
Gewijzigd op 08/03/2012 20:24:33 door Kris Peeters
Kris, het id-gebeuren moet dus altijd met een database werken?
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.
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)
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
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>
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)
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
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;
}
}
?>
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)
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
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);
}
})();
// 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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}
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
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