ahoj jak vytvořit efektivní online chat ??? napadlo mě že bych v intervalech vysílal pomocí ajaxa požadavky do php souboru a pokud by v databázi nebo v nějakém serverovém souboru objevil nový zápis tak by ho poslal a javascript by ho pak zase zobrazil. Dále mě napadlo že intervaly by v podstatě mohl vysílat i samotný serverový php skript (pomocí funkce sleep) a zátěž by přešla z klienta na server nicméně stejně by tam byla. Nejlepší by bylo vyřešit to pomocí událostí nicméňě nevím jestli se to dá vůbec nějak zapsat. Máte někdo radu??
Zkus kouknout na tohle: http://www.installfest.cz/if13/archiv - příspěvěk Real-time web by Adam Hořčica
Klasické "pingování" je sice možnost, ale lepší je využít websockety, nebo socket.io. Tyto technologie umožňují XHR polling (neplést s pooling). Vtip je v tom, že nastavíte timeout XHR requestu třeba na minutu, ten na serveru "zmrazíte" a až bude co zobrazovat, tak pošlete data. (Po timeoutu vytvoříte nový request) Reakce je okamžitá a máte realtime chat, bez zbytečného overheadu. Nevím jestli se toto dá řešit v PHP, já toto používám v nodeJS. (třeba Nette framework má určité metody freeze,store nad http requestem, ale ty jsem nestudoval)
Po zkušenostech doporučuji nenechat zkončit request na timeoutu, ale pár sekund před vypršením ho ukončit a nechat lienta vytvořit nový.
NodeJS by jsem se nebál, taky píšu weby v PHP, to je prostě pohodlnost... Pouze určité rutiny mám v nodeJS.
http://meteor.com/
Jednoduchý example v Ruby (server) HTML/JS (client).
server:
require "socket"
require "thread"
threads = [ ]
messages = [ ] # simpmle array of strings
mut = Mutex.new
$port = 2000
webserver = TCPServer.new('127.0.0.1', $port)
puts "Starting listening on port #{$port}..."
Thread.new {
while true
sleep 5
mut.synchronize { threads.each{|t| threads.delete t if t.status == false } }
end
}
while ($session = webserver.accept)
mut.synchronize {
# Forking data and processing
session = $session
t = Thread.new {
request = session.gets
reply = ''
puts "Request: #{request}"
if request.index('check')
sleep 5 if messages.count == 0
m = messages.join('","')
m = '"'+ m + '"' if m.length > 0
reply = '{"messages":['+ m +']}'
messages.clear
elsif request.index('post')
reply = '{"status":"ok"}'
threads.each{|t| t.wakeup if t.status == 'sleep' }
messages << "Hi"
else
reply = '{"error":"Bad request"}'
end
session.print "HTTP/1.1 200/OK\r\n"
session.print "Content-Length: #{reply.length}\r\n"
session.print "Access-Control-Allow-Origin: *\r\n"
session.print "Content-Type: text/html\r\n\r\n"
session.print reply
session.close
}
# Joining and continuing...
threads << t
}
end
puts "Shutting down..."
klient:
<html>
<head>
<title>REST test</title>
<script type="text/javascript">
var last_check = 0
var last_error = false
function check()
{
if (Date.now() < last_check+5000 && last_error) {
setTimeout(function(){check()}, 5000);
return;
}
last_check = Date.now();
var req = new XMLHttpRequest();
req.open("GET","http://localhost:2000/?check",true);
req.onreadystatechange = function() {
if (req.readyState==4 && req.status==200) {
var text = req.responseText;
var c = document.getElementById('console');
c.innerHTML += text;
setTimeout(function(){check()}, 100);
last_error = false;
}
else if (req.readyState==4 && req.status==0) {
setTimeout(function(){check()}, 5000);
last_error = true;
}
}
req.send();
}
</script>
</head>
<body onload="check()">
<div id="console"></div>
</body>
</html>
Tenhle příklad počítá na serveru se dvěma požadavky, jeden zařazuje fixní zprávu do fronty, druhý kontroluje frontu, pokud v ní něco je, pokračuje hned, v případě prázdné fronty vlákno na chvíli uspí. Pokud mezitím v jiném vlákně přijde nová, probudí se a okamžitě pošle odpověď, jinak se pošle odpověď s prázdným polem. Šlo mi jen o vláknování a reakci probuzení při změně stavu, plnou funkcionalitu tam nehledej.
Vcelku snadno to jde ale rozšířit frontu o vlákna pro jednotlivé uživatele, zakomponování vlastní zprávy atd. Vyloženě se na toto hodí nějaký ,,vlastní" způsob (proto Ruby listener na jiném portu), s použitím webserveru/skriptu přes CGI bys nejspíš nepochodil, primárně kvůli tomu, že se tím v drtivé většině zpracovává každý požadavek ve vlastním anonymním vlákně a někam výš se dostane jen těžko.