Farklı ihtiyaçlar, farklı çözümleri beraberinde getiriyor. Kullanıcılara sayfa değişmeden, sayfada olan değişiklikleri göstermek için genellikle AJAX tekniğini kullandık. AJAX’ın yetersiz kaldığı bir durumdan bahsetmek istiyorum. Diyelim ki, anlık 100 bin online ziyaretçisi olan bir sitemiz ve buna bağlı bir sayfamız olsun. Sayfadaki bazı verileri, AJAX yardımı ile 5 saniyede bir değiştirmek istedik. Bunun sonucunda her 5 saniyede bir, istemciden sunucuya istek yollanacak. 100 bin istemci olduğu için tam 100 bin istek. Çok masraflı, sunucuların baş belası bir durum. Peki bu durumu nasıl optimize edebiliriz? Bu sorunun cevabı COMET programlama tekniğidir.
COMET sunucu ile istemci arasında sonsuz süreli bir bağlantı açılarak yapılır. Şimdi anlatacağım yöntem twitter, facebook, gmail gibi büyük organizasyonlarda kullanılan yöntemle birebir aynıdır.
COMET’in diğer adları: Ajax Push, Reverse Ajax, Two-way-web, HTTP Streaming ve HTTP server push
Uygulama
Ufak bir kendi kendimize mesajlaşma uygulaması 🙂
[ İndirmek için tıklayınız ]
index.html
<html> <head> <title>Comet Programlama</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <style> body { margin:0px; padding:0px; overflow:hidden; } #msg { margin:0px; padding:10px;width : 700px; height:300px; overflow-y:scroll; border:1px solid #000; } #send{ width: 700px; height:100px; overflow-y:scroll; } </style> <script src="jquery.js"></script> <script type="text/javascript" charset="utf-8"> // COMET kısmı var timestamp = null; function comet() { $.ajax({ type : 'get', url : 'oku.php?timestamp=' + timestamp, async : true, cache : false, success : function(data) { var json = eval('(' + data + ')'); if(json['msg'] == ''){ $('#msg').html('Mesaj Yok!'); }else { $('#msg').html(json['msg']); $('#msg').animate({scrollTop: $('#msg').get(0).scrollHeight},1000); } timestamp = json['timestamp']; setTimeout('comet()', 1000); }, error : function(XMLHttpRequest, textstatus, error) { alert(error); setTimeout('comet()', 15000); } }); } // Mesaj Gönderme ve sonrasında veri dosyamıza yazma kısmı $(function() { comet(); $('#send').bind('keyup', function(e) { var msg = $(this).val(); if(e.keyCode == 13 && e.shiftKey) { return ; }else if(msg!='' && e.keyCode == 13) { $.ajax({ type : 'GET', url : 'yaz.php?msg='+ msg.replace(/\n/g,'<br />'), async : true, cache : false }); $(this).val('') } }) }); </script> </head> <body> <div id="msg"> </div> <br /> Mesaj : <br /> <textarea id="send" name="msg"></textarea> </body> </html>
Bu dosya iki ana bölümden oluşmaktadır. Birincisi COMET, veriyi okuduğumuz kısım. İkincisi ise, mesak gönderdiğimiz yani dosyaya yazma kısmı.
COMET kısmında oku.php dosyasına şuandaki timestamp değerini yani data.txt dosyasını en son düzenlediğimiz zamanı gönderiyoruz. Sonuç başarılı ise (sonucun başarılı olması aynı zamanda, dosyada değişiklik olduğu anlamına gelir) veriyi uygun biçimde ekrana bastırıyoruz ve 1 saniye sonra çalışmak üzere fonksiyonumuzu ayarlıyoruz. Sonuç başarısız ise ekrana hatayı uyarı şeklinde verdirip, fonksiyonu tekrar 15 saniye sonra çalışması için ayarlıyoruz. Burada kafanız karışabilir. Sürekli 1 saniyede 1 defa çalışıyor diye düşünebilirsiniz. Ancak dikkatli olmak gerek. Verinin geldiği dosyayı, oku.php dosyasını incelerseniz sonuç, data.txt dosyasında değiliklik olduğunda dönüyor. Yani değişiklik olmadığı sürece herhangi bir istek gerçekleşmiyor çünkü var olan istek henüz tamamlanmadı.
Gördüğünüz gibi yaptığımız istek sürekli pending (beklemede) olarak gözüküyor.
Yazma kısmı çok basit, textbox elementine yazılan metni enter tuşuna bastığımız anda yaz.php dosyasına gönderiyoruz.
oku.php
<?php $filename = 'data.txt'; $last = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0; $current = filemtime($filename); while( $current <= $last) { usleep(100000); clearstatcache(); $current = filemtime($filename); } $response = array(); $response['msg'] = file_get_contents($filename); $response['timestamp'] = $current; echo json_encode($response); ?>
Eğer varsa, index.html dosyasından en son yapılan işlem zamanını yani, yazma işleminin zamanını alıyoruz. Bu zamanı dosyanın düzenlenme zamanı ile karşılaştırıyoruz. Herhangi bir değişiklik yoksa bu kontrolü tekrar yapmak üzere bir saniyenin onda biri kadar bekliyoruz. Eğer dosyada değişiklik yapıldıysa, dosyadaki veriyi ekrana bastırıyoruz.
yaz.php
<?php $msg = $_GET['msg']; $file = 'data.txt'; $handle = fopen($file, 'a'); fwrite($handle, $msg); fclose($handle); exit; ?>
index.html dosyasından bize göndrilen mesajı data.txt dosyasına (‘a’ append) yani ekliyoruz.
data.txt: İlk başta içeriği boş.
Faydalanılan kaynaklar:
1-) A Simple Guide to Long Polling in 5 Minutes #nettuts
| https://www.screenr.com/SNH
at 21:00
Hocam bu bildiğin 1 saniyede veri kontrol olayı.Tek farkı veritabanına bakmıyor onun yerine dosyadan veri çekiyor.Ha jquery’de setInterval ile her bir saniye de veri çektin ha bunu yaptın.Aynı şey.İnsanları kandırmanın manası yok
at 00:29
Selamlar. Lütfen uygulamayı indirin ve daha sonra data.txt dosyasına rastgele veri ekleyin(Başkası mesaj göndermiş gibi düşünebilirsiniz). Eklediğiniz verinin anında uygulamaya yansıyacağını göreceksiniz. Burada gerçekleşen şey uzun süreli bir bağlantı açıp, bu bağlantı içerisinde dosyanın güncellenme tarihine bakarak, değişikliği yansıtmak. Yani dediğiniz gibi yapı yok. Hatta [ buraya tıklayarak ] zaman çizelgesinde bulunan 30.03 saniye (Uzun süreli bağlantı. Bu süre, veri değişimine bağlı olarak değişir ve sabit değildir) sonra veri geldiğine dikkat ediniz.
Sizden ricam, yorum yazarken verilen emeği, karşınızdakinin bilgisini bir de kendimizi ölçerek yorum yapalım.
Teşekkür ediyorum. Sevgi & Saygı.
at 01:18
Merhabalar.Hocam biz iki yazılımcı arkadaş comet teknolojisine merak saldık.İlk mesajı arkadaşım benim adıma yazar gibi göndermiş bu konudan dolayı özür dilerim.Ben ona yayınladığınız sistemin nasıl çalıştığını gösterdim ve kendisi de ikna oldu 🙂 Verdiğiniz yararlı bilgilerden dolayı şükranlarımı sunarım.İlk mesajı düzeltiyorum sisteminizde hiç bir sorun yok gayet güzel çalışıyor.Saygılar…
at 21:16
hocam peki aynı şeyi mysql ile nasıl yapacağız? Facebook şu işi nasıl hallediyor o kadar araştırmama rağmen hala bulamadım. Programlama çalışıyorum baya da yok kat ettim ama bu konu çok canımı sıktı.
at 01:33
Merhabalar.
Makale üzerindeki örnekten gidecek olursak, şöyle bir düşündüğümde ilk aklıma gelen:
yaz.php dosyasında verilerimizi veritabanına ihtiyaca göre, zaman damgası (TIMESTAMP) yani time() veya microtime() ile kaydedip;
oku.php dosyasında bunun kontrolünü sağlamak oldu.
İyi geceler.
at 18:10
bunun ajaxtan bir farkı yok çünkü saniyede bir dosyayı okuyor tarihine bakıyor. yani mysql yapmış olsaydık saniyede bir veritabanını okuyacaktı. Php nin 30 sn de dönmesi önemli değil sonuçta o 30 saniyede 30 sorgu yapıyor. Flash socket gibi bir bağlantı arıyorum bende???
at 18:17
Öncelikle bu yöntem ajaxtan çok farklı bir yöntem. Baktıysanız örneğimiz dosya ile çalışan bir örnek. Veritabanı ile değil. Her problem farklı bir çok çözümü beraberinde getirir.
Dediğinize karşılık şöyle bir çözüm geldi aklıma. Yaz.php dosyasında verimizi veritabanına yazarken veri dosyası olarak kullandığımız txt dosyasını null veri ile güncellemek. Bahsettiğim şey şu işe yarayacak: Verinin değişip değişmediğini txt dosyasının güncellenme tarhinden anlayacağız. Eğer güncellendiyse veritabanından veriyi çekip ekrana bastıracağız. Biraz hamallık oldu sanırım. Dahi iyi bir çözüm için okumaya devam.
Bunun yanı sıra MemCache kullanarak çok daha hızlı bir çözüm elde edebiliriz. MemCache kullanarak verinin güncellenme tarihini diskte değilde ram de tutmuş oluruz. Bu da bize büyük bir performans artışı sağlar. Umarım yardımcı olabilmişimdir.
at 10:44
Projem var ve bir yeri yapamıyorum yardım ederseniz sevinirim.
at 14:49
Hocam öncelikle merhaba bunu txt olarak değil de mysqldan veri çekerek yapabilir miyiz? Eğer yapılabiliyorsa nerelerde değişiklikler yapılması gerekli yardımcı olurmusunuz?
at 14:53
Yorumları yorum yaptıktan sonra okudum aynı soruyu başka bir arkadaş sormuş pek bilgim yok AJAX ve Java kullanımında oku ve yazı değiştirmemizi söylemişsiniz değiştirilmiş şekilde kodlamayı atabilirseniz çok sevinirim