@PsiCat; paylaşım için teşekkürler. Böyle bi anda yığınla kod epey karışık geldi ama incelicem.
Kusura bakmayın. Sanırım bazı açıklamalar yapmadan, paylaştığım kodların da aslında bir yararı olmayacak.
Öncelikle Node.js ile programlamaya başlamadan önce
Coffeescript dilini incelemenizi öneririm. Coffeescript, özellikle, herhangi bir ek Javascript kütüphanesine gerek kalmadan, saf Javascript kodları ile kolayca nesne yönelimli programlar yazmanız konusunda yardımcı olabilir. Coffeescript ile kodlarınızı yazıp çalıştırmak için basitçe NPM ile Coffeescript kütüphanesini indirin ve kodlarınızı aşağıdaki şekilde çalıştırın;
$ coffee server.coffee
"Derlenmiş Javascript kodları" başlığındaki kodları incelemenize gerek yok. O kodlar Coffee script ile yazdığım kodların Javascript'e çevrilmiş halleri. Yani asıl incelemeniz gereken kodlar "Coffeescript kodları." başlığındaki kodlar. Sanırım bu kodları da anlaşılır şekilde, PHP karşılıkları ile birlikte biraz açıklamam yerinde olur.
Not: Sadece Sunucu sınıfını açıkladım. Sunucu sınıfını anlarsanız Client sınıfını da anlayabilirsiniz.
1. Burada bir "Server" sınıfı oluşturuyorum ve "Singleton" tasarım kalıbını uyguluyorum. Zira program akışı sırasında ikinci sunucuya ihtiyaç yok. Dahası ikinci bir sunucunun oluşturulmaması şart. Ayrıca programın her yerinde sunucuya
Server.get() methodu ile ulaşabilirim.
class Server
instance = null
@get: ->
unless instance?
instance = new @
instance._init()
instanceclass Server
{
private static $instance = null;
public static function get()
{
if(!isset(static::$instance))
{
static::$instance = new Server();
static::$instance->_init();
}
return static::$instance;
}
}2.
_init; sunucu çalıştırıldığında çağırılan ilk metod.
clients bağlanacak kullanıcıları muhafaza edecek olan dinamik, boş bir nesne.
io ise
socket.io nesnesi.
_init: ->
@clients = { }
@io = require("socket.io")public $clients;
public $io;
private function _init()
{
$this->clients = new stdClass();
$this->io = require("socket.io");
}3.
_initCallbacks sunucunun başlatılması ile,
start metodu tarafından çağrılan ve sunucunun yerleşik
socket.io işelmlerini, sınıf metodlarına yönlendirecek olan metoddur.
authorization ile gelen her bağlantıyı, bağlanma aşamasında kontrol edebiliriz. Böylece geçersiz kullanıcı bilgileri ile giriş yapmaya çalışan kişilerin istekleri ile sunucu arasında bir kontrol katmanı eklemiş oluruz. Normal şartlarda
authorization her kullanıcıyı kabul eder.
_initCallbacks: =>
@io.set 'authorization', @_authorization
@io.sockets.on "connection", @_onConnect
private function _initCallbacks()
{
$this->io->set('authorization', $this->_authorization);
$this->io->on('connection', $this->_onConnect);
}4. Burada çok basit bir kontrol söz konusu. Bağlanan kullanıcının kullanıcı adının şu an sunucuya başlı olup olmadığı kontrol ediliyor. Eğer bu kullanıcı adı alınmış ise
'Bu kullanıcı su an bagli.' şeklinde bir hata ile kullanıcıyı geri çeviriyor. Mantıken burası kullanıcı adı ve şifresini veritabanından karşılaştıracağınız en iyi nokta. Bazı kişiler soket bağlantısını kabul ettikten sonra bu kontrolü '
onLogin' gibi ikinci bir istekte yapıyorlar ancak ben bunun tasvip etmiyorum.
_authorization: (handshake, callback) =>
username = handshake.query.username
handshake.username = username
for id, client of @clients
return callback('Bu kullanıcı su an bagli.', false) if client.username == username
callback(null, true)private function _authorization($handshake, $callback)
{
$username = $handshake->query->username;
$handshake->username = username;
foreach($clients as $client)
if($client->username == $username)
return $callback('Bu kullanıcı su an bagli.', false);
return $callback(null, true);
}
5.
_authorization kontrolleri akabinde eğer kullanıcının soket bağlantısı kabul edilirse
_onConnect metodu çağrılır. Kabul edilmeyen bağlantılar sunucu katmanına ulaşamadan geri çevrilir. Burada kullanıcının soketi ile yeni bir
Client nesnesine oluşturulur ve
clients değişkenine kaydedilir. Böylece sunucuya bağlanan bütün kullanıcılar üzerinde istediğiniz her türlü işlemi ve takibi kendi kurallarınız ile gerçekleştirebilirsiniz. socket.io aslında bu tür işlemler için bazı yerleşik imkanlar sunuyor ancak bunlar sadece çok basit işlemler için kullanılmaya müsait. Daha güçlü ve esnek bir kontrol için bu tür bir nesne yönelimli yapı kullanmanız daha faydalı.
_onConnect: (socket) =>
@clients[socket.id] = new Client(@, socket, socket.handshake.username)
private function _onConnect($socket)
{
$this->clients->{$socketId = $socket->id} = new Client($this, $socket, $socket->handshake->username);
}6.
start açıkça belli olduğu üzere sunucuyu başlatan metoddur. Buradaki önemli nokta
io örnek değişkeninin
listen metodu üzerinden dönen
socket.io manager nesnesine atanması. Sınıfta kullandığımız pek çok metod aslında bu nesneye aittir. İkinci olarak
io üzerinde gerekli olan
callback metodlarını tanımlamak için
_initCallbacks metodu çağrılıyor.
start: =>
@io = @io.listen(3000)
@_initCallbacks()
console.log("Sunucu dinliyor.")public function start()
{
$this->io = $this->io->listen(3000);
$this->_initCallbacks();
echo "Sunucu dinliyor.";
}7.
sendAll ile sunucuya bağlı olan bütün kullanıcılara mesaj gönderebilirsiniz.
sendAll: (args...) =>
@io.sockets.emit.apply(@io.sockets, args)
public function sendAll()
{
call_user_func(array($this->io->sockets, 'emit'), func_get_args());
}8. Gerekli noktalarda herhangi bir Client nesnesine ulaşmak istediğinizde socket ID değeri ile bu kullanıcıya ulaşabilirsiz.
getClient: (id) =>
@clients[id]
public function getClient($id)
{
return $this->clients->{$id};
}