View Sidebar
JQuery Comet Programlama

JQuery Comet Programlama

Aralık 30, 2012 13:018 yorum

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

chart

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ı.

bekleme

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
| http://www.screenr.com/SNH

8 Yorum

  • Murat

    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

    • Ulvi

      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ı.

      • Murat

        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…

  • ercan

    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ı.

    • Ulvi

      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.

  • sercan

    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???

    • Ulvi

      Ö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.

  • Güney

    Projem var ve bir yeri yapamıyorum yardım ederseniz sevinirim.

Yanıtla