Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Comet-tekniikka

Sivun loppuun

punppis [06.09.2009 23:43:39]

#

Kiinnostuin tuosta "Comet"-tekniikasta PHP:n kanssa ja se herättää kysymyksiä. Tällähän siis saadaan interaktiivisia sovelluksia tehtyä siten, että serveri lähettää tietoa selaimelle sitä mukaan kun siihen on tarvetta, eikä sitä tarvitse ajaxilla kysellä turhaan. Näin säästyy kaistaa ja tieto saadaan samantien käyttäjälle, kun jotain tapahtuu.

Ilmeisesti PHP:n kanssa siis tehdään vain while-silmukka, joka tarkastaa esim. tietokannasta että onko siellä mitään uutta tulostettavaa käyttäjälle.

Tässä siis ne kysymykset:
- tulostaako flush()-funktio tämän hetken tulostukset selaimelle, vaikka scriptin suoritus on kesken (sen while-silmukan takia)?
- pitääkö serveriltä olla tuo skriptin suoritukseen oleva aikarajoitus pois päältä, vai miten tämä rajoitus kierretään?
- miten serveri tietää, että koska se skriptin suoritus lopetetaan (eli kun käyttäjä sammuttaa selaimen tai haluaa lopettaa manuaalisesti). vai toimiiko tämä jotenkin automaattisesti?

Metabolix [07.09.2009 00:10:37]

#

- Ehkä.
- Pitää, ks. set_time_limit.
- Yleensä suoritus loppuu, kun painetaan sitä ruksinappulaa tai poistutaan sivulta. Jos skripti tekee jotain pitkää operaatiota, joka ei saa jäädä kesken, pitää käyttää ignore_user_abort-funktiota. Tuolla sivulla onkin esimerkki, jossa jäädään silmukkaan, kunnes käyttäjä katkaisee yhteyden.

punppis [07.09.2009 00:44:08]

#

Koitin yksinkertaisella koodilla tuota flushin käyttöä, mutta ainakaan suoraan selaimella katsottaessa mitään ei tulosteta ennenkuin tulee tuo suoritusaikaraja täyteen.

<?php
while(1) {
    echo time();
    flush();
    sleep(1);
}
?>

Millä tuon tulosteen saa sitten näytille kun tuo systeemi ei ainakaan tulosta mitään? Tai tulostaahan se, kaikki time()-funktion tulostukset n sekunnin ajalta n sekunnin päästä (n = suorituksen aikaraja). Pitäisi saada kerran sekunnissa tulemaan siis se aika.

T.M. [07.09.2009 02:37:11]

#

laita molemmat: ob_flush(); flush();

punppis [07.09.2009 13:50:37]

#

T.M. kirjoitti:

laita molemmat: ob_flush(); flush();

<?php
	$time = time();
	while($time+10 > time()) {
		echo time()."<br/>";
		ob_flush();flush();
		sleep(1);
	}
?>

Eipä toimi tuollakaan koodilla. Tein tuon 10sec rajoituksen tuohon, ettei tarvitse aina odottaa sitä 90sec mikä on itsellä suorituksen aikaraja.

Metabolix [07.09.2009 14:01:46]

#

Kannattaa ehkä aloittaa siitä varmemmasta tapauksesta, jossa palvelin sulkee yhteyden, kun tieto on saatu lähetettyä. Tässähän kaistaa säästyy siksi, että ei tarvitse tehdä uusia AJAX-kyselyitä parin sekunnin välein vaan sama kysely pidetään auki, kunnes on jotain kerrottavaa. Esimerkiksi chatin voi helposti toteuttaa tällä tekniikalla: palvelin vastaa pyyntöön sitten, kun joku lähettää uuden viestin, ja yhteys suljetaan saman tien.

Välissä ovat web-palvelinten, TCP:n ja selainten puskuroinnit. Ensimmäisen voi toivottavasti kiertää jollain flush-funktiolla, kahdelle muulle taas ei voi juuri mitään. TCP ei onneksi panttaa dataa loputtomiin, mutta selain saattaa tietyissä tilanteissa tehdäkin niin. Esimerkiksi XHTML:n vaatimuksiin kuuluu, että sivua pitäisi käsitellä vasta, kun se on ladattu kokonaan. (Tosin monet selaimet käsittelevät sen etuajassa samalla tavalla kuin HTML:n.)

Omalla palvelimellani on tulosteen puskurointi käytössä, joten tarvitaan sekä flush() että ob_flush(). Näiden kanssa data kyllä näytti tulevan perille aivan odotusten mukaan.

<?php
header("Content-Type: text/plain");
for ($i = 0; $i < 5; ++$i) {
        echo "$i";
        flush();
        ob_flush();
        sleep(1);
}

punppis [07.09.2009 14:24:20]

#

Joo tietysti tekisin sen sillain, että tietoa lähetetään vasta kun on tarvis, mutta en ole vielä onnistunut lähettämään sitä dataa selaimelle kesken skriptin suorituksen. Ajattelin kokeilla ensin tuon varsinaisen taustaskriptin toimintaa, ennenkuin rupean säätämään ajaxin kanssa. Toimiiko tuo skripti sitten erilailla esim. ajaxin kautta haettuna ja suoraan selaimella katsottuna?

Ajattelin tuon cometin käyttätarkoitusta esim. foorumisoftassa yksityisviestin ilmoittamisesta ilman erillistä sivunlatausta. Kun skripti tarkistaa uusia viestejä esim. 10 sekunnin välein niin silloinhan sitä skriptin suoritusta ei kannata sammuttaa koskaan, vai kuinka?

Toisaalta tuo 10sec välein viestien tarkistaminenkin rasittaa yhtä paljon serveriä kuin ajax, mutta vältytään datan lähettämiseltä serveriltä clientille (ja toisinpäin). Onko tähän vielä jotain järkevämpää systeemiä, jolla viestin saisi välittömästi vastaanottajalle?

T.M. [07.09.2009 22:10:16]

#

Metabolix kirjoitti:

Omalla palvelimellani on tulosteen puskurointi käytössä, joten tarvitaan sekä flush() että ob_flush(). Näiden kanssa data kyllä näytti tulevan perille aivan odotusten mukaan.

sullon väärin päin noi funkkarit, pitäs olla: ob_flush(); flush();

punppis [07.09.2009 22:38:27]

#

En ole vieläkään saanut toimimaan tuota tekstin tulostamista kesken skriptin suorittamisen, mutta jos oletetaan että minulla on toimiva taustaskripti, niin miten saan javascriptillä näytettyä sitä dataa livenä?

Lebe80 [07.09.2009 23:12:07]

#

Ajax -tekniikalla saat haettua dataa esim. t sekunnin välein.

punppis [07.09.2009 23:49:36]

#

Olen ymmärtänyt, että comet on käytännössä vain yksi pitkä ajax-kysely. Millä saan sitten tietoa tuolta comet-skriptiltä selaimelle?

peg [08.09.2009 00:19:57]

#

ai näin

<?php
if (ob_get_level() == 0) {
    ob_start();
}
echo str_pad('Etana latailee... ',4096)."<br />\n";
for ($i = 0; $i < 25; $i++) {
    echo '<span class="pbar">&nbsp;</span>';
    ob_flush();
    usleep(400000);
}
ob_end_flush();

?>

Metabolix [08.09.2009 21:12:35]

#

JS:llä voi ihmetellä sen kyselyobjektin responseText-arvon muuttumista.

Oletko aivan varma, ettei tuo minunkaan laittamani koodi (sellaisenaan) toimi? Minulla ainakin numerot ilmestyvät selaimeen (Fx) yksitellen.

punppis [08.09.2009 23:03:22]

#

Metabolix kirjoitti:

JS:llä voi ihmetellä sen kyselyobjektin responseText-arvon muuttumista.

Oletko aivan varma, ettei tuo minunkaan laittamani koodi (sellaisenaan) toimi? Minulla ainakin numerot ilmestyvät selaimeen (Fx) yksitellen.

Omalla koneellani Windows 7 + Wamp ja selaimena Operaa ja Firefoxia testattu. Ei toimi ei.

peg [09.09.2009 15:31:05]

#

Mitä tapahtuu kun ajat tuon minun koodini.
kirjoita koodiin perään vaikka toimii, niin hetken kuluttua
koodin jälkeinen osa latautuu sivulle.

punppis [09.09.2009 23:00:59]

#

peg kirjoitti:

Mitä tapahtuu kun ajat tuon minun koodini.
kirjoita koodiin perään vaikka toimii, niin hetken kuluttua
koodin jälkeinen osa latautuu sivulle.

Ei toimi. Kaikki tulostus tulee kerralla selaimeen.

peg [10.09.2009 00:40:57]

#

Vika saattaa olla ihan tuossa usleep(400000);
kokeile vielä 4000000 yksi nolla lisää.

punppis [10.09.2009 01:00:41]

#

No eihän se nyt siinä sleepissä voi olla vikana jos selain odottaa monta sekuntia ja sitten vasta tulostaa kaiken kerralla.

T.M. [13.09.2009 02:41:15]

#

onko sulla HTML:ää seassa? selain ei välttämättä renderöi sivua jos tulostelet sulkemattomien elementtien sisälle jotain tällä tyylillä. katseleppas jos sivun lähdekoodista näkee mitään muutoksia tulosteessa kun se vielä latailee, jos sinne ilmestyy esim sen 1 sekunnin välein kamaa, niin sitten selaimes vaan ei osaa renderöidä sitä. (sun pitää avata se lähdekoodi useempaan kertaan, se ei päivitä sitä automaattisesti...)

kokeiles nyt alkuun ilman HTML:ää.

punppis [13.09.2009 09:14:46]

#

T.M. kirjoitti:

onko sulla HTML:ää seassa? selain ei välttämättä renderöi sivua jos tulostelet sulkemattomien elementtien sisälle jotain tällä tyylillä. katseleppas jos sivun lähdekoodista näkee mitään muutoksia tulosteessa kun se vielä latailee, jos sinne ilmestyy esim sen 1 sekunnin välein kamaa, niin sitten selaimes vaan ei osaa renderöidä sitä. (sun pitää avata se lähdekoodi useempaan kertaan, se ei päivitä sitä automaattisesti...)

kokeiles nyt alkuun ilman HTML:ää.

// loop.php
<?php
header("Content-Type: text/plain");
for ($i = 0; $i < 10; ++$i) {
        echo "$i";
        flush();
        ob_flush();
        sleep(1);
}
[/php]
Tuolla Metabolixin koodilla kokeilin ja homma menee niin, että kun painan apachen linkkiä tuolle loop.php:lle, niin ensin selain jää sille sivulle kymmeneksi sekunniksi josta sitä linkkiä painoin, jonka jälkeen ruudulle tulee teksti 0123456789. En siis saa edes koko sivua auki ennenkuin se on suoritettu loppuun. Toimisikohan tämä ajaxin kautta, vaikka ei selaimessa toimisikaan?

EDIT: Ajaxilla ihan sama juttu. Koodi suoraan [url "https://www.ohjelmointiputka.net/tiedostot/AJAX_perusGET_TXT.txt"]ohjelmointiputkan ajax-esimerkistä[/url], mutta yhtä funktiota muokattu:
[koodiphp]
		function kasitteleVastaus()
		{
			document.getElementById("data").innerHTML = Pyynto.responseText;
			document.getElementById("count").innerHTML += ".";
		}

Kun siis painan nappulaa, niin ensin count-diviin ilmestyy kaksi (2) pistettä, siitä 10 sekunnin päästä data-diviin ilmestyy 0123456789 ja count-diviin 2 pistettä lisää.

Asdin [14.09.2009 23:13:40]

#

Kokeillaanpa nyt sitten sellaista ääripäätä, että suljet mahdolliset antivirusohjelmat suorituksen ajaksi. Joskus kuullut juttuja, että ainakin panda (ja eiköhän jotkut muutkin) cacheaa ja skannaa sivun ennen sen näyttämistä.

Metabolix [15.09.2009 00:49:30]

#

punppis: Kopioin viestisi koodin tänne (linkki poistettu), ja minulla se ainakin toimii. Siitä voit tarkistaa, onko vika palvelimessasi vai selaimessasi.

jo123 [15.09.2009 11:03:26]

#

Itselläni kyllä toimii kaikki muut ketjuun pannut koodit (omalla palvelimella), muttei taas tuo Metabolixin linkki (kaikki numerot putkahtavat yhtäaikaa 10sek odotuksen jälkeen). Päätellen tästä en ihmettelisi ollenkaan vaikkei tuo toimisi pumppiksellakaan.

Asdin [15.09.2009 13:17:22]

#

Itselläni toimii metabolixin linkkikin.
Firefox/Win XP

jo123 [15.09.2009 14:49:21]

#

Tuo toimimattomuus johtuu toden näköisesti itselläni antivirus ohjelmasta. Suunnilleen samallaisella koneella toimii, samassa verkossa myös. Kummassakin on Firefox/Windows 7. Muuta mahdollisesti vaikuttavaa eroa ei nimittäin tule heti mieleen... Ihmetyttää silti tuo, että omalla palvelimellani toimii tällä toisellakin koneella.

Metabolix [15.09.2009 15:42:52]

#

jo123 kirjoitti:

Ihmetyttää silti tuo, että omalla palvelimellani toimii tällä toisellakin koneella.

Onko oma palvelin ehkä lähiverkossa?

jo123 [15.09.2009 15:47:08]

#

Metabolix kirjoitti:

jo123 kirjoitti:

Ihmetyttää silti tuo, että omalla palvelimellani toimii tällä toisellakin koneella.

Onko oma palvelin ehkä lähiverkossa?

Juu, ajattelinkin tuon olevan todennäköisin syy, siis jos se ylipäänsä on se (ei kyllä kauheasti muita vaihtoehtoja ole).

Edit: En kyllä suosittele tätä tekniikka pumppikselle, kun avast-antviruskin kaikessa yksinkertaisuudessaan näyttää estävän sen.

Metabolix [15.09.2009 16:20:38]

#

Ongelmat eivät onneksi estä sitä Comet-tekniikan toista versiota, että tehdään AJAX-kysely, joka on voimassa, kunnes palvelimella on jotain asiaa:

<?php
$time = (int) $_GET["time"];
if (!$time) die("Hyi, hakkeri!");
$time = date("Y-m-d H:i:s", $time);
while (count($viestit = hae_uudet_viestit($time)) == 0) {
  sleep(1);
}
tulosta_viestit($viestit);

Tämän jälkeen selaimen pitää lähettää uusi AJAX-kysely.

punppis [15.09.2009 21:48:41]

#

Juu ei toiminut tuo Metabolixin palvelimella oleva skripti Operassa eikä Firefoxissa. Ilmeisesti F-Secure 2010 blokkaa tuon. Tätähän ei siis missään nimessä kannata käyttää, kun ei toimi virustorjunnan kanssa. Pitänee kokeilla tuota Metabolixin toista vaihtoehtoa.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta