Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: plastik 25. 05. 2013, 20:28:52
-
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.