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.