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?
- 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.
Koitin yksinkertaisella koodilla tuota flushin käyttöä, mutta ainakaan suoraan selaimella katsottaessa mitään ei tulosteta ennenkuin tulee tuo suoritusaikaraja täyteen.
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.
laita molemmat: ob_flush(); flush();
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.
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.
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?
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();
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ä?
Ajax -tekniikalla saat haettua dataa esim. t sekunnin välein.
Olen ymmärtänyt, että comet on käytännössä vain yksi pitkä ajax-kysely. Millä saan sitten tietoa tuolta comet-skriptiltä selaimelle?
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"> </span>'; ob_flush(); usleep(400000); } ob_end_flush(); ?>
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.
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.
Mitä tapahtuu kun ajat tuon minun koodini.
kirjoita koodiin perään vaikka toimii, niin hetken kuluttua
koodin jälkeinen osa latautuu sivulle.
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.
Vika saattaa olla ihan tuossa usleep(400000);
kokeile vielä 4000000 yksi nolla lisää.
No eihän se nyt siinä sleepissä voi olla vikana jos selain odottaa monta sekuntia ja sitten vasta tulostaa kaiken kerralla.
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:ää.
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ää.
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ä.
punppis: Kopioin viestisi koodin tänne (linkki poistettu), ja minulla se ainakin toimii. Siitä voit tarkistaa, onko vika palvelimessasi vai selaimessasi.
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.
Itselläni toimii metabolixin linkkikin.
Firefox/Win XP
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.
jo123 kirjoitti:
Ihmetyttää silti tuo, että omalla palvelimellani toimii tällä toisellakin koneella.
Onko oma palvelin ehkä lähiverkossa?
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.
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.
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.
Aihe on jo aika vanha, joten et voi enää vastata siihen.