8 Mayıs 2012 Salı

PHP Soket Programlama


Bu bölümde, bir makineye, programa ya da herhangi bir hedefe uzaktan bağlanmak ile ilişkili konu ve kavramlara değinilecektir.            

Soket Programlama

Soket kavramı, kısaca, web sunucu ile web tarayıcı arasındaki haberleşmeyi sağlayan bir metod olarak bilinmektedir. Bu bağlamda soketlere dosya demek yanlış olmayacaktır. Zira internette bulunan bütün programlar soket olarak çalışmaktadır ve bunların her biri birer dosyadır.

TCP/IP üzerinde, verilerin iletimi için IP adresi ve PORT numarası gerekmektedir. Bu iki bilgi, IP adresi:PORT numarası formatında yazıldığında ortaya bir veri çıkmaktadır. Bu veriye de soket adı verilmektedir.

Soket veri


Soket veri → 192.168.1.3:21


           
Yukarıdaki soket verisi, 192.168.1.3 IP adresine sahip bir makineye, 21 numaralı porttan bir bağlantı yapıldığını göstermektedir.

Bahsettiğimiz gibi soketler, haberleşmeyi sağlarlar. Daha önce üzerinde durduğumuz dosya işlemleriyle, soket programlama arasında pek bir fark olduğu söylenemez. Nitekim iki başlık içinde aynı kavramları görmek mümkündür.

İki taraf arasında iletişim sağlanabilmesi için IP adresine ve PORT numarasına ihtiyaç vardır demiştik. IP adresi muhtemelen bir bilgisayar, PORT numarası ise, bir programı temsil eden bir numara, dolayısıyla bir program olacaktır. Soket veriyi oluşturan bu kavramlara kısaca değinmekte yarar görüyorum.


IP Adresi

IP, TCP/IP protokol türünü kullanarak ağlara ya da doğrudan internete bağlanan makinelerin kullandıkları adreslere verilen addır. İnternet’e bağlı bir bilgisayarın tehlikelere daha açık olduğu herkes tarafından bilinir. Bunun sebebi şudur: İnternet bağlantısı olan her bilgisayara birer IP adresi atanır. Bu IP adresi, yerel ağda olsun veya olmasın her bilgisayar tarafından görülebilir. İki makine arasında bağlantı kurmanın yolu IP adresinden geçtiğine göre, iletişim kolaylıkla sağlanacak ve güvenlik açığı meydana gelecektir.


PORT Numarası

Soketler, iletişim sağlayabilmek için PORT numarasına ihtiyaç duyarlar. Çünkü bir makinede birden çok soket veri bulunabilmektedir. Bu sebeple, bağlantı kurulan programların birer numaraya sahip olması gerekmektedir. Bu numaraları birer ID numarası olarak düşünebiliriz. Aksi halde bağlantı sırasında karışıklık meydana gelebilmektedir. Sonuç olarak her programın sahip olduğu birer PORT numarası mevcuttur.

Örnek olarak bir bilgisayarda aynı anda ve sürede iki farklı soket veri bulunduğunu düşünelim. Bunlardan biri 21 PORT numaraları FTP (File Transfer Protocol) programını kullanırken, diğer soket veri, 110 port numaralı POP3 (Post Office Protocol) programını kullanmaktadır. Farklı PORT numaraları sayesinde karışıklık olmasının önüne geçilmektedir.

Bazı PORT Numaraları ve Protokoller

PORT


İletişim Türü


Program


Açıklama

4
UDP
NTP

13
TCP / UDP

Zaman Protokol
21
TCP / UDP
FTP
Veri Alım / Gönderim
23
TCP / UDP

Telnet Protokol
41
TCP / UDP

Grafik
53
TCP / UDP
DNS
Alan Adı
80
TCP
HTTP
Web Sayfa Yayınlama
110
TCP
POP3
E-mail Protokol
118
TCP / UDP
SQL

143
TCP / UDP
IMAP4
Mail Depolama
194
TCP
IRC
İnternet Aktarmalı Sohbet


Tablo, sık kullanılan bazı programları ve port numaralarını sıralamaktadır. Yukarıdaki tablo dikkatlice incelendiğinde bazı programların iletim türünün TCP, bazılarının UDP, bazılarının da her ikisi olduğu görülecektir. Bu protokoller arasındaki en bariz fark, TCP protokol türünün, bir veriyi gönderdikten sonra, veriyi alan taraftan bir iletim raporu gelmesini beklemesi ve daha güvenli bir haberleşme temin etmesidir. UDP türü protokol veriyi gönderdikten sonraki süreç ile ilgilenmez. Bu bağlamda inceleme yapılırsa yukarıdaki tablo’daki maddeler mantıklı bir şekilde yorumlanabilecektir.

Örneğin 194 port numarasına sahip IRC, internet aktarmalı sohbet, yani bilindik ismi ile CHAT, TCP protokol türünü tercih etmektedir. Çünkü chat kavramı en az iki kişi ile yapılmaktadır ve bir makineden gelen veri, diğerine ulaşmadıkça bu bir chat olmayacaktır. UDP seçilmeme sebebi veri gönderiminin kesinliğini garanti edemiyor olmasıdır.


Server (Sunucu)

Server kavramı, sunucu anlamına gelmektedir. Adından da anlaşılacağı gibi, hizmet veren soket programdır. Durmaksızın işlem görür, çünkü client program her an hizmet isteyebilmektedir

Client (İstemci)

Client, Türkçe dilinde istemci olarak bilinir. Sunucuya bağlanıp görevini yerine getirmektedir. Her an server ile bağlantı sağlamak isteyeceğinden dolayı server sürekli işlem görmek durumundadır.


Soket Türleri

Birçok soket veri türü vardır. Bunlardan bazıları en sıklıkla kullanılan, Stream, Datagram ve Raw soket veri türleridir. Yazılımsal olarak sırasıyla, SOCK_STREAM, SOCK_DGRAM ve SOCK_RAW olarak isimlendirilmektedirler. Herhangi bir soket programlama yapılacak ise soket türü belirtilmektedir. Stream soketler TCP’yi, Datagram soketler ise UDP’yi kullanmaktadırlar. Bu iki soket türü arasındaki farklar şöyle sıralanabilir:

Datagram soketler, verileri sıralı göndermez, Stream soketler ise sıralı gönderirler.
Datagram soketler veri çıkışı gerçekleştikten sonra bağlantıyı keser, Stream soketler ise veri gönderme işlemi tamamen bitene dek bağlantıyı sürdürür.
Stream soketler, iletişim ve haberleşme esnasında taşınan verinin bütünlüğünü ve veri akışını bozmamayı garanti eder, datagram soketler ise bu konuda bir güvence vermez. Bunun sebebi, tercih edilen protokol türleridir. Soket türleri bunlarla sınırlı değildir. Birçok soket türü vardır. Bunlardan bazılarını sıralamak gerekirse,

Bazı Soket Türleri
AF_INET
SOCK_RDM
SOCK_SEQPACKET
SOCKET_EINPROGRESS
MSG_EOR
SOCKET_EDQUOT
PHP_NORMAL_READ
SOCKET_EDUOT
AF_UNIX
SOCKET_EIO
PHP_BINARY_READ
SOCKET_EINTR
MSG_OOB
SOL_SOCKET
SOCKET_EBADF
SOCKET_ENOMEM
SOCKET_EACCES
SOCKET_EBUSY
SOCKET_EEXIST
SOCKET_EISDIR


Soket Fonksiyonları

Soket fonksiyonları, soket verinin görevini yerine getirmesi için gereken işlevselliği sağlarlar. Bu bölümde soket fonksiyonlarına değineceğiz.

Soket Fonksiyonları
socket_create()
socket_create_pair()
socket_create_listen()
socket_connect()
socket_bind()
socket_clear_error()
socket_get_option()
socket_accept()
socket_close()
socket_getpeername()
socket_getsockname()
socket_last_error()
socket_listen()
socket_read()
socket_recv()
socket_send()
socket_select()
socket_recvfrom()
socket_sendto()
socket_set_block()
socket_set_nonblock()
socket_set_option()
socket_shutdown()
socket_strerror()
socket_write()




socket_create()

Bu fonksiyon adından anlaşılacağı gibi, bir soket veri oluşturmaktadır. Bunu oluştururken, bazı parametrelere ihtiyaç duymaktadır.

socket_create() yapısı


socket_create(protokol ailesi, soket türü, protokol)



Protokol Ailesi

Daha önce soket türlerine değinmiştik. AF_INET bunlardan biri idi. socket_create() fonksiyonu tarafından kullanılması gerekli olan protokol türünü belirlemek için yazılacak ifade, protokol ailesi parametre değeri olarak bilinmektedir. AF_INET, AF_INET6, AF_UNIX gibi ifadeler almaktadır.

Soket Türü

Sayısız soket türü olduğunu bilmekteyiz. Bu parametre, herhangi bir soket türünü değer olarak almaktadır. Bu soket türleri, muhtemelen şu değerler olacaktır.

  • SOCK_STREAM
  • SOCK_DGRAM
  • SOCK_RAW
  • SOCK_RDW
  • SOCK_SEQPACKET
Protokol Türü

socket_create() fonksiyonu ile oluşturulan soket verinin iletişim türünü belirlemek için kullanılan bir parametredir. UDP, TCP ya da ICMP gibi değerler almaktadır.

socket_bind()

Belirtilen soket içerisinde bulunan adresin, bir isim ile ilişkilendirilmesini sağlar. Bu işlem soket oluşturulmadan önce yapılmalıdır.

socket_bind() yapısı


socket_bind(soket_veri, adres, port)


Yukarıda belirtilen parametreler içerisinde bulunan port, sıfır (0) değeri almaktadır. Çünkü socket_bind() fonksiyonu çalışmaya başladığı an, hali hazırda bulunan bir soket veri bulunmamaktadır. Zira socket_bind() fonksiyonu, socket_create() fonksiyonundan önce yapılandırılmaktadır.

socket_listen()

socket_listen() fonksiyonu, bir soketin socket_create() fonksiyonu ile oluşturulup, socket_bin() fonksiyonu vasıtasıyla da bir ağ ile isimlendirilmesi sonrası devreye girmektedir. Ve bu soket artık dinlenen bir soket olmaktadır. Ayrıca sadece SOCK_STREAM ve SOCK_SEQPACKET soket türleriyle bağlantı kurabilmektedir.

socket_accept()

Bir soketi oluşturmayı, isimlendirmeyi ve gelen bağlantıları algılamayı öğrendik. Buraya kadar ki işlemler, ancak gelen bir bağlantıyı dinlemeye yeterli olacaktır. Daha fazla bir işlev görülemeyecektir. socket_accept() fonksiyonu, buraya kadar olan işlemlerin uygulanmasının ardından, dinlenen bağlantıları kabul etmek işlevini gerçekleştirmeyi sağlayacaktır. Tek bir bağlantı için kullanılmaz. Birçok bağlantıyı dinlemek ve kabul etmek için bu fonksiyon işlev görecektir.
Bir hata olması durumu, bu fonksiyonun FALSE (0) değeri döndürmesine neden olacaktır.

fsockopen()

Bu fonksiyon socket_create() fonksiyonu ile görev olarak benzerlik göstermektedir. Bir internet soketi bağlantısı oluşturmaktadır.

fsockopen() yapısı


fsockopen(bağlantı adresi, port numarası, hata numarası, hata iletisi, zaman aşımı)



Uygulama


fsockopen("phpservisi.com", 80, "Bağlantı başarısız! ", 30)


Port numarası olan parametre, 80 olarak belirlenmiştir. Bu port numarası HTTP web sunucusu numarasıdır. Phpservisi.com adres olarak ayarlanmıştır. Zaman aşımı ise 30 olarak belirlenmiştir. Bu da saniye cinsinden bir değer almaktadır. Hata iletisi ise “Bağlantı Başarısız” olarak belirlenmiştir.

stream_socket_client()

stream_socket_client() fonksiyonu bir UNIX alan ya da bir ağ soket verisi oluşturmaktadır.  Uzak hedef olarak belirlenen bir URL’ye UDP ya da TCP olarak belirlenen protokol türü belirledikten sonra : (iki nokta) karakteri ile PORT numarası belirtip gerekli bağlantıyı sağlamaktadır.

stream_socket_client() yapısı


<?php
$baglan = stream_socket_client("TCP://www.phpservisi.com:80", $hatano, $hatamesaj, 30);
if (!$baglan) {
    echo "$hatamesaj ($hatano) ";
} else {
    fwrite($baglan, "GET / HTTP/1.0\r\nHost: www.phpservisi.com\r\nAccept: */*\r\n\r\n");
    while (!feof($baglan)) {
        echo fgets($baglan, 1024);
    }
    fclose($baglan);
}
?>



Yukarıdaki uygulama çalıştırılıp ekran görüntüsü alındığında aşağıdaki görüntü görüntülenecektir.

echo fgets($baglan, 1024);

Yukarıdaki satırda 1024 ifadesi görülmektedir. Bu 1024 bayt, yani 1 KB veri akışını ifade etmektedir.
stream_socket_client()
Soket Hata Fonksiyonları

Olumsuz şartlarda bütün soket veriler bağlantıyı kesebilir veya başarısız olabilir. Bu durumda birtakım hata iletileri devreye girer. Bu iletiler kullanıcının isteği dışında ekrana gelmektedir. Fakat bazı soket hata fonksiyonları vardır ki bunlar hataların kaydını alabilmektedirler. Bu bölümde bu hata fonksiyonları üzerinde durulacaktır.

 socket_strerror

Soketler olumsuz şartlarda hata raporu oluştururlar. Bunu sağlayan fonksiyon socket_strerror() fonksiyonudur.

socket_strerror() yapısı


socket_strerror(int $hatanumarasi)



Bir tamsayı değeri olan $hatanumarasi isimli değişken, socket_last_error() fonksiyonundan döndürülen hata numarasını temsil etmektedir.

socket_strerror(socket_last_error())


socket_last_error()

Adından da anlaşılacağı gibi, soket veride belirlenen son hatanın kodunu araştırmaktadır. Eğer hata verebilecek herhangi bir soket belirlenmez ise, oluşan son hata kodu alınacaktır.

socket_last_error() yapısı


socket_last_error(soket_veri)


Uygulamalar

Buraya kadar bir soket oluşturmayı, bağlantı yakalayıp bunu kabul etmeyi, uzaktan bir adrese bağlanmayı ve bunu okumayı, hata raporlamayı ve bütün bunları yapmayı sağlayan fonksiyonlar öğrendik. Bu bölümde uzaktan bir bağlantıyı çekme ile ilgili birkaç örnek uygulama yapılacaktır.

Uzaktan Bağlantı


<?php
$baglan = stream_socket_client("tcp://www.phpservisi.com:80", $hatano, $hatamesaj, 30);
if (!$baglan==0) {

    fwrite($baglan, "GET / HTTP/1.0\r\nHost: www.phpservisi.com\r\n: */*\r\n\r\n");
    while (!feof($baglan)) {
        echo fgets($baglan, 1024);
    }
    fclose($baglan);
}
?>



$baglan = stream_socket_client("tcp://www.phpservisi.com:80", $hatano, $hatamesaj, 30);

Yukarıdaki satırlar stream_socket_client() fonksiyonu ile TCP protokol türü seçerek ve PORT numarası 80 olan HTTP programını kullanarak bir web sayfasına bağlantıyı açma işlemini göstermektedir. Son parametre olan 30 sayısı, zamanı saniye cinsinden ifade etmektedir.

Bu program çalıştırılıp ekran görüntüsü alındığında, sayfa tam bir şekilde phpservisi.com adresini gösterecektir.

Uzaktan Bağlantı


<?php
$baglan = fsockopen("phpservisi.com", 80, $hatanumarasi, $hataraporu, 30);
if (!$baglan) {
    echo "$hataraporu($hatanumarasi)<br />\n";
} else {
    $aciklama = "GET / HTTP/1.1\r\n";
    $aciklama .= "Host: phpservisi.com\r\n";
    $aciklama .= "Connection: Close\r\n\r\n";
    fwrite($baglan, $aciklama);
    while (!feof($baglan)) {
        echo fgets($baglan, 128);
    }
    fclose($baglan);
}
?>



$baglan = fsockopen("phpservisi.com", 80, $hatanumarasi, $hataraporu, 30);
if (!$baglan) {

Yukarıdaki satırlar fsockopen() fonksiyonu ile PORT numarası 80 olan HTTP programını kullanarak bir web sayfasına bağlantıyı açma işlemini göstermektedir.

Bu program çalıştırılıp ekran görüntüsü alındığında, sayfa tam bir şekilde phpservisi.com adresini gösterecektir. Bir önceki uygulama ile aynı şekilde bir çıktı alınacaktır.


Bir sonraki yazıda görüşmek üzere!

1 yorum: