/*
* Bu belgenin telif haklar� Bar�� �im�ek'e aittir.
* K�k: http://www.acikkod.org
* S�r�m No: 6
* �lk bask�: 1998-11-10
* Son g�ncelleme: 2004-08-01
* Bu d�k�man A��kkod.ORG Belge Yaz�m ve Da��t�m Lisans� ile
* da��t�lmaktad�r.
*
*/

��indekiler

1. Soket Kavramlar�
2. TCP/IP Protokol�
    2.1. A� Eri�im Katman�
    2.2. A� Katman�
    2.3. Ta��ma Katman�
    2.4. Uygulama Katman�
3. Uygulamadaki Temel Prensipler
    3.1. Soket T�rleri
    3.2. Veri D�n���mleri
    3.3. Sistem �a�r�lar�
4. Sunucu Soket Program�
    4.1. Sistem �a�r�lar�n�n Kullan�m�
    4.2. sunucu.c
5. �stemci Soket Program�
6. Geli�mi� G/�
    6.1. Bloksuz G/�
    6.2. select()
7. S�k Sorulan Sorular
8. Belge Tarih�esi

1. Kavramlar

Soketler, ayn� veya farkl� hostlar �zerindeki s�re�lerin haberle�mesini sa�layan bir haberle�me (interprocessing) y�ntemidir. Soket, soyut bir tan�mla haberle�me u� noktalar�d�r. POSIX'in sa�lad��� programlama API'si sayesinde programc� soketlere yazarken veya okurken yine write,read gibi sistem �a�r�lar�n� kullanabilir.

�stemci (Client): Hizmet isteyen soket programlara denir.

Sunucu (Server): Hizmet veren soket programd�r.

Port: Bir bilgisayarda birden �ok soket bulunabilir. �rne�in hem telnet soketi, hem de ftp soketi a��k olabilir. Soketleri birbirinden ay�rt etmek ve istemciyi sunucudaki uygun program ile bulu�turmak i�in her soket program�n PORT denilen bir numaras� vard�r. �rne�in FTP protokol�n�n port numaras� 21, Telnet sunucunun port numaras� ise 23't�r. Standart servislerin port numaralar� /etc/services dosyas�nda tan�ml�d�r. 1-1024 aras�ndaki portlar yaln�z root taraf�ndan kullan�labilir, normal kullan�c�lar bu portlar� bind edemezler.

IP Numaras�: TCP/IP protokol� hostlar�, sadece kendisine ait olan bir IP numaras� ile tan�mlar. Bilgisayarlar birbiri ile IP numaras�n� kullanarak haberle�irler. Bir istemci soket program, �nce IP numaras�n� kullanarak sunucunun bulundu�u bilgisayara, sonra PORT numaras�n� kullanarak hizmet istedi�i sunucu program ile temasa ge�er. IPV4 standard�na g�re IP'ler 192.168.1.10 gibi [0-255].[0-255].[0-255].[0-255] format�na sahiptir. IPV6 standart� 128bit adres kullan�r.

Sarmalama(Encapsulation): Her katman kendisine gelen pakete bir ba�l�k ekler ve bir sonraki protokole aktar�r. Buna encapsulation (sarmalama) denir. Kar�� tarafta paket a��l�rken yine her katman kendisi ile ilgili ba�l��� a�ar. �rne�in fiziksel katman (mesela ethernet ayg�t�) g�nderen sistemin fiziksel katman�n�n ekledi�i ba�l��� a�ar. Zaten di�er ba�l�klar� yorumlayamaz. A�a��da sarmalanm�� bir paket g�r�lmektedir.

+----------------------+
|       Ethernet       |
|+--------------------+|
||         IP         ||
||+------------------+||
|||        UDP       |||
|||+----------------+|||
||||       DNS      ||||
||||+--------------+||||
|||||      Veri    |||||
||||+--------------+||||

2. TCP/IP Protokol�

TCP/IP, "Transaction Control Protocol and Internet Protocol" i�in bir k�saltmad�r. TCP/IP, DARPA(Defense Advanced Research Projects Agency) projesi olarak 1970'lerde Amerika'daki baz� devlet kurumlar�n� birbirine ba�lamak amac� ile geli�tirildi. Daha sonra BSD(Berkeley Software Distribution) UNIX'e eklenerek uygulama alan� buldu. TCP/IP'nin i�erdi�i protokollerin tan�mlar� RFC(Request For Comments)'lerde yap�lm��t�r. RFC'lere ula�mak i�in: http://www.faqs.org/rfcs/

TCP/IP 4 katmanl� bir modeldir: 1. Uygulama Katman� 2. Ta��ma Katman� 3. Internet Katman� 4. A� Eri�im Katman�. Her bir katman OSI modelindeki bir veya daha fazla katman�n i�levine sahiptir. 1982'de BSD UNIX ile TCP/IP uygulamalar� geli�tirildi.

2.1. A� Eri�im Katman�

Bu katman TCP/IP paketlerini fiziksel a�a b�rakmak ve ayn� zamanda fiziksel a�dan gelen paketleri almakla g�revlidir. OSI modelindeki Fiziksel katman ve Veri-Ba� katman�n�n kar��l���d�r.

2.2. A� Katman�

Bu katman adresleme, paketleme ve y�nlendirme fonksiyonlar�n� yerine getirir. IP, ARP, ICMP ve IGMP protokolleri, bu katmana ait �ekirdek protokollerdir.

Internet Protocol (IP): Adres bilgilerini ve paket y�nlendirme i�in baz� kontrol bilgilerini i�erir. RFC 791'de tan�mlanm�� olup en �nemli internet protokol�d�r. �ki �nemli g�revi vard�r: 1. A�lar aras�nda ba�lant�s�z datagram da��t�m�n� yapmak, 2. Fregmantasyon ve veri katman�na yard�mc� olarak de�i�ik MTU(maximum-transmission unit) de�erleri ile datagramlar� yeniden olu�turmak. IP paketinin ba�l�k yap�s� a�a��daki gibi tan�mlanm��t�r:

    0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |Type of Service|          Total Length         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Identification        |Flags|      Fragment Offset    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Time to Live |    Protocol   |         Header Checksum       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Source Address                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Destination Address                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Version: Kullan�lan internet ba�l���n�n bi�imini, versiyonunu g�sterir.
IP Header Length (IHL): Datagram ba�l���n�n 32 bit olarak boyutunu g�sterir. Do�ru bir IP ba�l��� i�in ba�l�k boyutu en az 5 olmal�.
Type of Service: �stenilen hizmet kalitesi ile ilgili soyut parametreler sunar. �rne�in baz� a�lar, �nceli�i destekler. Trafi�in bir k�sm�na �ncelik verilebilir.
Total Length: Ba�l�k ve veri bilgisi ile birlikte toplam datagram boyutunu g�sterir. 16 bittir, buradaki de�er byte olarak g�sterir. Yani IP paketi en fazla 64K boyutunda olabilir.
Identification: G�nderen taraf�ndan yaz�l�r. Datagram par�alar�n� biraraya getirmeye yard�mc� olur.
Flags: Paketin par�alanabilece�ini veya par�alanamayaca��n� g�sterir.
Fragment Offset: Bu paketin datagram i�erisinde nereye ait oldu�unu tan�mlar.
Time to Live: S�rekli azalan tam say�d�r. Paketin hangi noktada yok edilece�ini belirtir. Paketin sonsuza tek a�da kalmas�na engel olur.
Protocol: IP'nin i�i bittikten sonra paketi hangi �st protokol alaca��n� g�sterir.
Header Checksum: IP ba�l���n�n bozulmad���na emin olmak i�in tutulan de�er
Source Address: G�nderen noktay� g�sterir.
Destination Address: Al�c� noktay� g�sterir.
Options: IP, g�venlik gibi de�i�ik se�enekleri destekler.
Data: �st katmana verilecek veriyi tutar.

2.3. Ta��ma Katman�

Bu katman transparan bir �ekilde verinin hosttan hosta ta��nmas�n� sa�lar. Ak�� kontrol�n� ve hata d�zeltmeyi sa�lar. Veri transferinin bitti�inden emin olur. TCP ve UDP protkolleri bu katmana aittir. A� katman� ba�lant� y�nelimli (connection oriented) ba�lant� sa�lamaz. Ta��ma katman� bunu sa�lar. A� katman� ula�an paketlerin, g�nderildi�i s�rada ula�t���n� da garanti etmez. Ta��ma katman� her paketi numaraland�rarak bunu basit�e ��zer. Hata olu�tu�u durumda paketi yeniden ister. B�ylece olu�abilecek hatalar�n �n�ne kesilir.

Transmission Control Protocol (TCP): TCP, IP ortam�nda u�tan uca g�venli haberle�me sunan ba�lant� y�nelimli(connection oriented) bir protokold�r. RFC 793'de tan�mlanm��t�r. Uygulama katman�n�n hemen alt�nda bulunur. Ayn� zamanda s�re�ler aras� haberle�me(interprocess communication) prokol�d�r. �ki s�re� aras�nda sanal bir devre olu�turur. Telnet, TCP kullanan pop�ler uygulamalardan birisidir.

TCP, zarar g�rm��, kaybolmu� veya s�ras� bozulmu� veriyi kurtarabilir. Aktar�lan her sekizlik i�in s�ra numaras� tutar ve al�c� noktadan olumlu ACK(Acknowledge-ald���n� bildirmek) bekler. E�er ACK, bir zamana��m�(timeout) s�resi i�erisinde gelmezse veri yeniden aktar�l�r. Al�c� taraf verileri s�ral� almam�� veya geciken ACK'lerden dolay� birden fazla alm�� olabilir. TCP bunlar� d�zeltir. Her bir segmente bir kontrol toplam�(checksum) eklenerek al�c� taraf�n ald��� verinin do�ru olup olmad���n� denetlemesi sa�lan�r. TCP'nin di�er protokoller ile ili�kisi:

  +------+ +-----+ +-----+       +-----+
  |Telnet| | FTP | |Voice|  ...  |     |  Uygulama Seviyesi
  +------+ +-----+ +-----+       +-----+
        |   |         |             |
       +-----+     +-----+       +-----+
       | TCP |     | RTP |  ...  |     |  Host Seviyesi
       +-----+     +-----+       +-----+
          |           |             |
       +-------------------------------+
       |    Internet Protocol & ICMP   |  A� Ge�idi Seviyesi
       +-------------------------------+
                      |
         +---------------------------+
         |   Local Network Protocol  |    A� Seviyesi
         +---------------------------+

TCP, veri stream'lerini birbirinden ay�rt etmek i�in port tan�mlay�c� kullan�r. Her TCP birbirinden ba��ms�z port tan�mlay�c� sunar. Bu nedenle port tan�mlay�c�lar tek olmayabilir. Bu nedenle soket olu�turulurken internet adresi de kullan�l�r.

Bir ba�lant� tamamen u�lardaki soketler aras�nda olu�ur. Yerel bir soket pek �ok d�� soket ile ba�lant� yapabilir. Ba�lant� iki y�nl� veri ta��mada (full duplex) kullan�labilir.

TCP segmentleri internet datagramlar� olarak g�nderilir. ��nk� alt�nda IP protokol� vard�r. TCP segmentleri, IP taraf�ndan paketlenip g�nderilir. TCP ba�l��� a�a��daki gibidir:

    0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

User Datagram Protocol (UDP): RFC 768'de tan�mlanm��t�r. Bu protokol uygulamalar i�in en az protokol y�k� ile haberle�me olana�� sa�lar. Protokol i�lemi ger�ekle�tirmeye y�neliktir. Da��t�m ve g�venli�i temin etmez. Checksum de�eri tutar ancak paket bozulmu�sa yeniden paketi da��tmaz. Ba�l�k yap�s� �u �ekildedir:

 0      7 8     15 16    23 24    31
 +--------+--------+--------+--------+
 |     Source      |   Destination   |
 |      Port       |      Port       |
 +--------+--------+--------+--------+
 |                 |                 |
 |     Length      |    Checksum     |
 +--------+--------+--------+--------+
 |
 |          data octets ...
 +---------------- ...

DNS ve tftp bu protokol� kullanan en pop�ler uygulamalard�r.

Bu iki t�r�n �zellikleri ve aralar�ndaki temel farklar� ��yle s�ralayabiliriz:

1. Stream soketler verileri s�ral� g�nderir, datagram soketleri s�ral� g�ndermeyebilir. (TCP protokolu, paketleri s�ral� g�ndermeyi garanti eder. UDP garanti etmez. TCP paketlerin ba�l�k bilgisinde s�ra numaras� vard�r, UDP'de yoktur. TCP, her zaman s�radaki paketi ister. �rne�in 4 numaral� paket yerine 5 numaral� paket eline ula��rsa kar�� tarafa bunu bildirir ve 4'� ister. 4'� al�nca da 5'ten �nceye koyar.)

2. Stream soketler g�venlidir, Datagram soketler g�vensizdir. (TCP protokolu g�venli�i garanti eder, UDP garanti etmez. ��nk� TCP acknowledgement ile denetim yapar. Yani bir paketi g�nderdi�i zaman, kar�� taraf paketi ald���n� haber vermeden o paketi g�ndermi� saymaz kendini ve tekrar g�nderir. ayr�ca paketin do�ru gidip gitmedi�ini anlamak i�in ba�l�k bilgisinde checksum -kontrol bilgisi- tutar. UDP'de checksum tutar ancak checksum yanl��sa ayn� paketi tekrar istemez.)

3. Stream soketler, i�lem bitene kadar kesintisiz bir ba�lant� kurar. Datagram soketler ise ba�lant� kurmaz. Sadece veri g�nderece�i zaman ba�lant� kurar ve i�i bitince ba�lant�y� kopar�r.

Bu iki aras�ndaki fark� anlatmak i�in postac� ve telefon benzetmesini verece�im. Mektup insanlar aras�nda haberle�meyi sa�layan bir y�ntemdir. Postac� mektuplar� posta kutusuna b�rak�p gider. Ki�i ise mektuplar� m�sait oldu�u herhangi bir an (belki 1 saat sonra, belki 1 g�n, belki 1 hafta) al�r ve okur. Cevab�n� yine posta kutusuna atar ve postac� bir s�re sonra mektuplar� al�p kar��ya ta��r. Telefon �rne�inde ise, bir taraf di�er tarafa telefon a�ar. Aradaki ba�lant� kurulduktan sonra insanlar ba�lant� kopmadan kar��l�kl� konu�urlar. Posta �rne�inde ba�lant�n�n s�reklili�i gibi bir �ey s�z konusu de�ildi. Telefon g�r��mesinde s�zlerin s�ral� gitmesi s�z konusu. Yani s�zler birbirine kar��maz. Ancak postada ise durum farkl�. Mektuplar kar�� tarafta s�ral� okunmayabilir. �rne�in posta kutusunda 5 mektup birikince mektuplar�n� okur. Telefonda ise kar��l�kl� s�rekli konu�ulur ve s�ylenen kar��ya iletilir.

UDP'nin bu kadar tez avantaj�na ra�men neden daha �ok kullan�ld��� bu �emalardan a��k�a g�r�lmektedir. TCP bir veri kar��ya 6x32+Veri boyu kadar bir paket olarak gitmektedir. Yani her paket fazladan 192 bit ba�l�k (header) bilgisi ta��maktad�r. Oysa UDP paketleri 64 bitlik ba�l�k (header) bilgisine sahiptir.

UDP kullanman�n en �nemli nedeni az protokol y�k�d�r. Video sunucu gibi realtime veri ak��� gerektiren bir uygulama i�in TCP fazla y�k getirir ve g�r�nt� realtime oynamaz. Bu nedenle multicast uygulamalar�nda Datagram soketler kullan�l�r. Ayr�ca video ve ses g�r�nt�lerinde genelde az bir veri kayb� sesi veya g�r�nt�y� bozmaz. Bu nedenle s�k� paket kontrolune gerek yoktur. E�er iyi bir fiziksel ba�lant�n�z varsa hata oran� d���k olacakt�r ve bu nedenle TCP'nin yapt��� hatal� paket kontrol i�lemleri fazladan y�k olacaktir.

UDP her ne kadar kendisi paket g�venli�ini denetlemese de bunu yaz�l�mc� yapabilir. �rne�in TCP bir paketi g�nderdi�inde kar�� taraf�n onu ald���n� anlamak i�in acknowledgement bekler. UDP bunu yapmaz. Fakat bunu soket yaz�l�mc�s� yapabilir. Yaz�l�mc�, g�nderilen her pakete bir cevap bekleyerek bunu sa�lar.

2.4. Uygulama Katman�

TCP/IP protokol�n�n en �st�nde yer al�r. Ta��ma katman�n�n sa�lad��� UDP ve TCP protokollerini kullanarak veri aktar�m� yapabilirler. Telnet, FTP, SMTP, HTTP uygulama katman� protokolleridir.

3. Uygulamadaki Temel Prensipler

Soketler her zaman iki uca sahiptir: Al�c� ve g�nderici. B�t�n mesajlar ve protokol gere�i olan ba�l�klar nihayetinde fiziksel katmandan, mant�ksal 1 ve 0'a kar��l�k gelen elektriksel sinyaller olarak g�nderilir.

Soket program ya istemci, yada sunucudur. Programlar� daha kar���k olmakla beraber baz� soket programlar her iki g�revi de yapmaktad�r. Sunucu program ile istemci program aras�nda �al��ma olarak baz� farklar vard�r. A�a��daki tablo her iki tarafta olaylar�n nas�l gitti�ini g�stermektedir:

 ---------------------------------------------------------------------------
|          �stemci        |                    Sunucu                       |
|---------------------------------------------------------------------------|
|                         | Soket olu�tur, socket()                         |
|                         |-------------------------------------------------|
| Soket olu�tur, socket() | Adres bilgilerini yerle�tir struct  sockaddr_in |
|                         |-------------------------------------------------|
|                         | Soket ad�n� adresi ile ili�kilendir bind()      |
|                         |-------------------------------------------------|
|                         | Soketi dinlemeye ge�, bind()                    |
|---------------------------------------------------------------------------|
| Ba�lant� yap, connect() | Ba�lant�y� kabul et, accept()                   |
|-------------------------|-------------------------------------------------|
| Veri g�nder, send()     | Veri al, recv()                                 |
|-------------------------|-------------------------------------------------|
| Veri al, recv()         | Veri g�nder, send()                             |
|-------------------------|-------------------------------------------------|
| ...                     | ...                                             |
| Di�er i�lemler          | Di�er i�lemler                                  |
| ...                     | ...                                             |
|---------------------------------------------------------------------------|
| Soketi kapat, close()   | Soketi kapat, close()                           |
 ---------------------------------------------------------------------------

3.1. Soket T�rleri

Tan�ml� pek �ok soket t�r� vard�r. Ancak u d�k�manda en �ok kullan�lan 3 t�rden bahsedilecektir.

SOCK_STREAM: S�ral�, g�venli, iki yollu, ba�lant� y�nelimli (connection oriented) veri ak��� sa�lar. Veri al��veri�inden �nce ba�lant� (connect) yap�lm�� olmal�. Paketin kaybolmad���n� veya birden �ok gelmedi�ini uygulama katman�na garanti eder. Kabul edilebilir bir s�re i�erisinde veri transferi sa�lanamazsa ba�lant� yok varsay�l�r.

SOCK_DGRAM: Datagram ba�lant�s� sa�lar. Datagramlar, ba�lant�s�z (connectionless), g�venilir olmayan paketlerdir.

SOCK_RAW: TCP/IP ye raw olarak (herhangi bir format ve s�n�r olmadan) ula�may� sa�lar.

Raw soketler ba�l� ba��na bir konu olup detayl� bilgi i�in Murat Balaban'�n yazd��� http://www.acikkod.org/yayingoster.php?id=34 d�k�man�ndan faydalanabilirsiniz. Datagram ve stream soketleri 2.3. Ta��ma Katman� k�sm�nda tart���ld�.

3.2. Veri D�n���mleri

�nsanlar�n soldan sa�a veya sa�dan sola alfabelere sahip olmalar� gibi i�lemciler de byte'lar� saklarken �nemli byte'�n solda veya sa�da olmas�na g�re s�n�fland�r�l�r. Buna endianness da denir. Arap rakamlar�nda oldu�u gibi (�ngilizce veya T�rk�ede kulland���m�z rakamlar) �nemli byte'�n solda oldu�u s�ralamaya big-endian denir. �nemli byte'�n en sa�da oldu�u s�ralama ise Little Endian olarak adland�r�l�r.

B�t�n i�lemciler kendi s�ralamas�n� se�mi�tir. i386 ve klonu olan i�lemciler little endian'd�r. Sun Sparc, Motorola 68K ve PowerPC big endian kullan�r. Java Sanal ��lemcisi (Java VM) de big endian kullan�r.

Farkl� iki i�lemcisi olan makineler birbirileri ile haberle�ecekleri zaman (IPC), bu veri d�n���m�n� yapmazlar ise haberle�emezler.

A� protokolleri de kendi s�ralamas�n� se�melidir. Aksi takdirde iki farkl� mimarideki bilgisayar IPC yaparak birbirileri ile haberle�ecekleri zaman anla�amayacaklard�r. TCP/IP big endian s�ralamas�n� kullan�r. Bunun anlam� �u: Herhangi bir paket (IP adresi, paket uzunlu�u, kontrol de�eri gibi) g�nderilece�i zaman en �nemli byte'� �nce g�nderilir ve al�n�r.

�ki t�r byte s�ralamas� vard�r. En �nemli byte'�n �nde geldi�i s�ralama ki buna Network Byte S�ralamas� denir ve �nemli byte'�n sonra geldi�i d�ralama. Buna da Host Byte S�ralamas� denir. Bu ikisi aras�ndaki d�n���mler a�a��daki d�rt fonksiyon taraf�ndan yap�lmaktad�r:

#include <netinet/in.h>

uint32_t htonl(uint32_t hostlong); /* Host to Network Long */
uint16_t htons(uint16_t hostshort); /* Host to Network Short */
uint32_t ntohl(uint32_t netlong); /* Network to Host Long */
uint16_t ntohs(uint16_t netshort); /* Network to Host Short */

E�er iki host da little endian ise veri transferinden �nce network byte s�ras�na �evirilmeli. Al�nan tarafta tekrar little endian'a �evrilir.

�u senaryoyu dikkatle inceleyelim inceleyelim: Intel bir makine internet �zerinden SPARC makine ile haberle�ecek. Veri olarak 192.168.1.254 gibi bir IP adresini d���nelim. Intel i�lemci little endian olarak bunu 0xFE01A8C0(254 1 168 192) �eklinde tutar ve FE-01-A8-C0 s�ras�yla bunu g�nderir. SPARC makine bunu ayn� s�rada alacak ve bu s�rada kullanacak. ��nk� big endian kullan�r ve �nemli olan en ba�ta gelir. Dolay�s�yla SPARC bu IP adresini 254.1.168.192 olarak alg�lar.

Programc� hostlarda hangi s�ralaman�n kullan�ld���n� bilmek zorunda de�il. Yukar�daki d�n��t�r�c� fonksiyonlar kendi i�lemcileri ile ilgili d�n���mleri otomatik olarak yapacakt�r.

Veriler a� �zerinde network byte s�ras� ile dola�acakt�r. Veriyi alan host makina ntohl ile bu veriyi kendi anlad��� s�raya �evirecektir.

3.3. Sistem �a�r�lar�

Adres atamas�:

Gerek sunucu, gerekse istemci internet adres bilgilerini tutmak i�in sockaddr_in yap�s�n� kullan�r. Bu yap�n�n a��l�m� �u �ekildedir:

struct sockaddr_in {
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}

Bu yap� i�erisinde bir ba�ka yap� daha vard�r. Bu yap� in_addr yap�s�d�r ve a��l�m� ��yledir:

struct in_addr {
union {
struct { u_char s_b1, s_b2, s_b3, s_b4; } S_un_b;
struct { u_short s_w1, s_w2; } S_un_w;
u_long S_addr;
} S_un;
}

Bu yap�lar� do�rudan kullanmayaca��z; o nedenle rahat olun. Ancak ilk yap�n�n temel yap�m�z oldu�unu unutmay�n. Bu yap� i�erisinde IP adreslerini ve port numaralar�n� saklayaca��z. 

�nsanlar bir ba�lant� ger�ekle�tirecekleri zaman genelde host isimlerini kullan�rlar. Oysa internetteki hi�bir makine host ismini kullanmaz. "cclub.ktu.edu.tr" bir host ismidir. 193.140.168.77 bu hostun sahip oldu�u IP adresidir. Host isimlerini IP adreslerine �eviren sistemlere DNS (Domain Name Server) denir.  ��letim sistemi bize DNS i�lemlerini yapmak i�in k�t�phane sunmaktad�r. IP d�n���m� yapmak i�in k�t�phane �a�r�lar�ndan gethostbyname() 'i kullanabiliriz.

#include <netdb.h>
struct hostent* host;
host = gethostbyname("cclub.ktu.edu.tr");

Soket Olu�turma:

�ki program�n haberle�mesi i�in �ncelikle her iki tarafta da soket a��lmas� gerekir.

int socket(int domain, int type, int protocol);

socket() fonksiyonunun ikinci parametresi soketin tipidir. Buraya: 

SOCK_STREAM 
SOCK_DGRAM 
SOCK_RAW 
SOCK_SEQPACKET 
SOCK_RDM 
SOCK_PACKET

gibi soket t�rlerini yazabiliriz. �lk ikisini yukar�da anlatt�m. Di�erlerinin ne anlama geldi�i �u a�amada �nemli de�ildir. Yaln�zca biz SOCK_STREAM tipini kulland���m�z i�in ikinci parametre olarak bunu verdi�imizi bilin. Yani bu bir stream sunucu soket uygulamas�d�r.

���nc� parametresi protocol tipini belirler. Hali haz�rda 5 protokol t�r� vard�r : 

AF_UNIX (UNIX internal protocols) 
AF_INET (ARPA Internet protocols) 
AF_ISO (ISO protocols) 
AF_NS (Xerox Network Systems protocols) 
AF_IMPLINK (IMP "host at IMP" link layer) 

Soket ile ilgili tan�mlamalar�n ba�l�k dosyalar� sys/types.h> ve <sys/socket.h> dir.

Veri Al��-veri�i:

Birbiri ile ba�lant�s� yap�lm�� iki soket aras�nda art�k veri al��-veri�ine ba�layabiliriz. Buradaki veriler kar��ya ta��nmas� gereken ger�ek veriler olabilece�i gibi, kar��ya yapmas� gereken i�leri bildiren bir komut listesi olabilir. Her �ey, iki program aras�nda taraf�n�zdan tan�mlanm�� protokol �er�evesinde olacakt�r.

write() ve read() fonksiyonlar� ayn� zamanda dosya i�lemleri i�in de kullan�l�r.  send() ve recv() ise bu fonksiyonlar�n soketler i�in �zelli�tirilmi� halidir.

int send(int s, const void *msg, int len, unsigned int flags);
int recv(int s, const void *msg, int len, unsigned int flags);

4. Sunucu Soket Program�

4.1. Sistem �a�r�lar�n�n Kullan�m�

Bu kadar teorik bilgiden sonra bir uygulama yapmaya ge�ebiliriz. 2222 numaral� portta �al��an basit bir sunucu program� �zerinde olaylar� inceleyelim. Bundan sonra �zerinde �al��aca��m�z kodlar sunucu i�in yaz�lmaktad�r. �stemci program olarak standart telnet program�n� kullanaca��z. Mimari olarak sunucu yaz�l�mlar�n, istemci yaz�l�mlardan farkl� oldu�unu unutmay�n. A�a��daki kodlar� gcc C derleyicisi kullanarak yazd�m. Ancak bu kodlar tamamen standart olup Windows alt�ndaki Visual C derleyicisi ile de �al��abilir. De�i�ik platformlarda sorun yatmas�n diye kod i�erisinde T�rk�e karakter kullanmad�m.

�nce port numaram�z� belirleyelim:

#define PORT 2222

S�ra soket olu�turmada:

int sockfd;
sockfd=socket(AF_INET,SOCK_STREAM,0); 
if (sockfd<0) { 
  perror("socket"); 
  exit(1); 
}

Burada verdi�im kodlar tek ba��na �al��maz. Daha kolay anla��ls�n diye programdan par�alar bir araya getiriyorum. En sonunda �al��abilir kodun tamam�n� verece�im. Bu i�lemlere ba�lamadan �nce baz� header (.h) dosyalar�n�n y�klenmesi gerekir. Bunlar� da kodun tamam�nda g�rebilirsiniz.

Yukar�daki kodu incelersek: Soket olu�turma i�lemini socket() fonksiyonu ile yap�yoruz.

socket() fonksiyonu geriye bir tamsay� de�er d�nd�r�r. Hata olu�umunda bu de�er -1'dir. E�er hata olu�mazsa geri d�nen de�er soketin tan�mlay�c� numaras�d�r. Bu numara en ba�ta bahsetti�imiz gibi dosya tan�mlay�c�s�d�r. Bu numaray� kodda g�r�ld��� gibi sockfd de�i�kenine atat�m. Bu i�lemden sonra soketi takip etmek i�in art�k sockfd de�i�kenini kullanaca��m. Olu�turulan her soket bu �ekilde ayr� bir numara al�r.

Hata kontrol� yapmaya �zen g�sterin. Aksi halde zaman�z�n b�y�k bir k�sm�n� programdaki hatalar� ay�klamak ile ge�irirsiniz.

�imdi port numaras�n�n atamas�n� yapal�m:

if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1) { 
  perror("bind"); 
  exit(1); 
}

bind() fonksiyonu soketi isimlendirir. socket() ile olu�turulmu� bir soket i�in isim uzay�nda (bellekte) vard�r ancak bir isme sahip de�ildir. Bind i�lemi belirtilen port numaras�n� ve gerekli sistem kaynaklar�n� i�letim sisteminden ister. E�er bu i�lemi yapmazsan�z i�letim sistemi port havuzundan herhangi bir port atar. Port numaras�n� belirlemezseniz, di�er insanlar sizin programla haberle�ecek programlar yazamaz. bind() fonksiyonu ayn� zamanda sizi bir veya daha fazla a� arabirim kart�ndan (Network Interface Card) yal�t�r. A� �zerindeki her host bir NIC'a sahiptir ve her NIC en az bir IP adresine sahiptir. addr.sin_addr de�eri olarak INADDR_ANY yazmakla i�letim sistemine host �zerinde bulunan m�mk�n b�t�n IP adreslerinden ba�lant� kabul edece�inizi s�yl�yorsunuz. Bunu istemiyorsan�z makinenin sahip oldu�u IP numaralar�ndan birini, hizmet vermek �zere se�ebilirsiniz. E�er �zerinde bulundu�unuz makine bir firewall ise belirlenmi� bir IP'yi kullanmak yarar�n�za olacakt�r. Bu �ekilde firewall'un yaln�zca bir y�z� hizmet sunacakt�r.

if (listen(sockfd, 5) == -1) {
  perror("listen");
  exit(1);
}

bind() i�leminden sonra sunucumuz art�k istemcileri beklemeye ba�layabilir. �stemcilerin kabul edilebilmesi i�in sunucunun �ncelikle dinlemeye ge�mesi gerekir. Bunun i�in listen() fonksiyonunu kullan�r. Bu �a�r�, soketin �zelliklerinde baz� de�i�iklikler yapar. �rne�in soketi dinleme moduna ge�er ve bu soketi veri ta��mas� i�in kullanamazs�n�z. listen(), �a�r�ld�ktan sonra parametre olarak belirtti�iniz kadar bir bekleme kuyru�u olu�turur. Yukar�da parametre olarak 5 verdik. Bunun anlam�: Sunucu mevcut ba�lant�ya hizmet verirken gelecek ilk 5 istek bekleme kuyru�una konulacak. Sunucu s�rayla bunlara hizmet verecek.

Art�k sunucu ba�lant� kabul etmek i�in soketi dinlemeye alm��t�r. Herhangi bir istemcinin ba�lant� iste�ini accept() �a�r�s� ile yakalayaca��z. Kab�l fonksiyonu program� G/� bekleme durumuna sokar. Dolays�yla program�m�z i�letim sistemi taraf�ndan bloke edilir ve ba�lant� iste�i geldi�inde tekrar uyand�r�l�r.

int accept(int s, struct sockaddr *addr, int *addrlen);

Kab�l i�lemi, gelen iste�i yeni bir soket ile kar��lar. ��nk� mevcut soketimiz dinleme durumundad�r ve veri ta��ma i�lemi ger�ekle�tiremez.

�imdi program�m�z�n tamamland���n� ve cclub.ktu.edu.tr hostunda �al��t���n� varsayal�m.

cclub:~> telnet cclub.ktu.edu.tr 2222

Ge�ici olarak telnet program�n� istemci olarak kulland�m. "telnet" i bir echo istemcisi gibi d���n�n. Sunucu ne g�nderirse onu ekrana basar. 2222 portuna ba�lant� iste�i g�nderdi�imizde sunucu program�m�z bize yeni bir soket a��p ba�lant�m�z� kabul edecek. Telnet ile sunucumuzun konu�mamas� i�in hi�bir neden yok.

�stemcilerin adres bilgileri, ba�lant� kab�l� s�ras�nda al�n�r. accept() fonksiyonun son parametresi bir girdi de�il ��kt�d�r. Ba�lant� s�ras�nda bu yap� doldurulup programa d�nd�r�l�r. Biz programa d�nen adres bilgilerini kullanarak programlar�m�za biraz renk katabiliriz. �rne�in, istemcinin adresini al�p bir yasak dosyas�nda var m� diye kontrol ederiz. E�er varsa ba�lant�y� red ederiz. Ba�lant�lar� k�s�tlayan /etc/hosts.deny ve serbestlik tan�yan /etc/hosts.allow dosyalar�n� hat�rlay�n. Sanki bir �eyler hat�rlar gibi olduk de�il mi?

int fd, client_size; 
struct sockaddr_in client_addr; 
client_size = sizeof(struct sockaddr_in); 
fd = accept(sockfd, (struct sockaddr *)&client_addr, &client_size)); 
printf("Merhaba %s",inet_ntoa(client_addr.sin_addr));

Sunucumuza bir ba�lant� yap�ld���nda sunucu ekrana "Merhaba 193.140.168.54" gibi bir �ey yazacak. G�rd���n�z gibi ba�lant� yapan�n adresini de ald�k.

4.2. sunucu.c

// sunucu.c - Stream soket sunucu
// Baris Simsek,<simsek at acikkod org>
// http://www.acikkod.org


#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>

#define PORT 3333
#define LISTQUEUE 5

main(int argc, char *argv[])
{
  int sockfd, new_fd;
  struct sockaddr_in server_addr, client_addr;
  int client_size;
  char buffer[1024];

  printf("%s %d portu uzerinde calismaya basladi...\\n\\n",argv[0],PORT);

  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }

  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(PORT);
  server_addr.sin_addr.s_addr = INADDR_ANY;

  if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
    perror("bind");
    exit(1);
  }

  if (listen(sockfd, LISTQUEUE) != 0) {
    perror("listen");
    exit(1);
  }

  while(1) {
    client_size = sizeof(struct sockaddr_in);
    if((new_fd=accept(sockfd,(struct sockaddr*)&client_addr,&client_size)) == -1) {
      perror("accept");
      exit(1);
    }

    printf("%s sunucumuza baglandi...\\n",inet_ntoa(client_addr.sin_addr));

    memset(&buffer, 0, sizeof(buffer));
    strcpy(buffer,"Merhaba ");
    strcat(buffer,(char *) inet_ntoa(client_addr.sin_addr));
    strcat(buffer," :)\\n");

    if (send(new_fd,&buffer, strlen(buffer), 0) == -1) perror("send");
    if (recv(new_fd,&buffer, strlen(buffer)-1, 0) == -1) perror("recv");
    printf("Alinan yanit: %s\\n", buffer);

    close(new_fd);
  }
  close(sockfd);
  while (waitpid(-1,NULL,WNOHANG) > 0); 
  return 0;
}

Evet. ��te harika d�nyaya ad�m att�k ve "Merhaba" dedik. Bunu ilk denedi�imde g�zlerime inanamam��t�m. Ba�ka bir bilgisayardaki ki�iye merhaba demi�tim. O zamanlar chat programlar� bu kadar populer de�ildi. Bu ger�ekten harika bir �ey.

�imdi program�m�z� linux alt�nda "GNU C Compiler" gcc ile nas�l derleyece�imizi g�relim.

cclub:~> gcc -o sunucu1 sunucu.c

Bu komutla sunucu.c dosyas�na yazd���m�z kodlar� derleyip sunucu1 isimli �al��abilir dosyay� �rettik. Bakal�m neler oluyor:

cclub:~> ./sunucu1
./sunucu1 2222 portu uzerinde calismaya basladi...
193.140.168.54 sunucumuza baglandi...

Tahmin edece�iniz gibi bunlar sunucunun ekran�na yazanlar. "193.140.168.54 sunucumuza baglandi..." mesaj�, ceng hostundan ba�lant� yap�ld���nda ekrana bas�lm��t�r. Peki istemcinin ekran�na neler d�n�yor:

ceng:~# telnet 193.140.168.77 2222 
Trying 193.140.168.77... 
Connected to 193.140.168.77. 
Escape character is '^]'. 
Merhaba 193.140.168.54 :)

Merhaba 193.140.168.54 :) mesaj�, sunucu taraf�ndan istemcimize (telnet) g�nderilen mesajd�r. Onun �st�ndeki mesajlar� merak etmeyin. Onlar�n bizimle ilgisi yok. Telnet'in �retti�i mesajlard�r. Windows makineden "Ba�lat->�al��t�r" kullanarak ayn� komutu verebilirsiniz.

5. �stemci Soket Program�

�imdi istemci bir soket program�n genel yap�s�na bakal�m. Ba�lang�� a�amas�nda i�lemler sunucu program ile ayn� olacakt�r. Ancak as�l i� yap�lan k�s�mda hem mimari, hem de fonksiyonlar de�i�eek. ��nk� bir taraf hizmet verme, �teki taraf ise hizmet alma durumunda olacakt�r. �imdi geli�tirece�imiz istemci yukardaki sunucu i�in geli�tirilmemi�tir. Bu program�m�z 3333 numaral� portta �al��s�n. Bu istemci program i�in bir de sunuu program yazd�m. Sunucu program�n �al��mas�n� yukar�da anlatt���mdan tekrar bu program i�in de anla. Bu program�m�z 3333 numaral� portta �al��s�n. Bu istemci program i�in bir de sunuu program yazd�m. Sunucu program�n �al��mas�n� yukar�da anlatt���mdan tekrar bu program i�in de anlatmayaca��m. Do�rudan kodunu vermekle yetinece�im.

�ncelikle port numaram�z� belirleyelim:

#define PORT 3333

Sunucunun �al��t��� bilgisayar istemciye parametre olarak verilecek:

int main(int argc, char *argv[])
{
  if (argc != 2) {
    printf("Kullanimi : %s hostname ",argv[0]);
    exit(1);
  }
}

Sunucunun Belirlenmesi:

Parametre olarak al�nan host ismini ��z�ml�yoruz. Adres yap�s�nda olan server_addr de�i�kenine PORT numaras�n� ve IP adresini yaz�yoruz.

struct hostent *h_name;

if(argc > 1) {
  h_name = gethostbyname(argv[1]);
}
else {
  printf("Kullanimi: %s hostname ",argv[0]);
  exit(1);
}

bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = *(u_long *) h_name->h_addr;
serv_addr.sin_port = htons(PORT);

printf("Sunucu adresi: %s ",inet_ntoa(serv_addr.sin_addr));

Sunucuya Ba�lanma:

Art�k hizmetkar�m�za, yani sunucumuza ba�lan�p selam verme vakti geldi.

printf("Mesajinizi girin: ");
fgets(buf, sizeof(buf)+1, stdin);

if((send(sockfd, buf, sizeof(buf), 0)) <= 0) perror("send");
if((recv(sockfd, buf, sizeof(buf), 0)) <= 0) perror("recv");
printf("Sunucu'dan gelen mesaj: %s", buf);

shutdown(sockfd, 2);
close(sockfd);

Aynen sunucu programda oldu�u gibi soket a�t�k. Soket t�r�m�z yine SOCK_STREAM. Sonra connect()fonksiyonunu kullanarak a�t���m�z soket �zerinden bir ba�lant� yapt�k. connect() fonksiyonu sys/types.h ba�l�k dosyas�nda a�a��daki gibi tan�mlanm��t�r:

int connect(int s, const void *addr, int addrlen);

�lk parametre soket tan�mlay�c�s�, ikinci parametre ba�lant� kurulacak sunucunun adres bilgilerini i�eren server_addr yap�s�, son parametre ise adres yap�s�n�n boyutudur. Art�k sunucumuzla aram�zda stream bir soket ba�lant�s� kurmu� olduk. �stemci taraf�nda connect() yap�ld��� zaman, sunucu taraf�nda accept() yap�l�r. Yani yap�lan ba�lant� kabul edilir. Daha �nce yazd���m�z sunucu programdaki accept() i�lemi, telnet program�n�n connect() iste�ini kar��l�yordu. �imdi bizim istemimiz bu iste�i g�nderecek. Dikkat ederseniz ilkel bir telnet program� yaz�yoruz.

Sunucuya Bilgi G�nderme:

Sonraki k�sm�, anla��lmas� a��s�ndan basit tuttum. Ekrandan bir mesaj al�p bunu send() fonksiyonu ile sunucuya g�nderiyoruz. Bu fonksiyon, dosyalara yazmak i�in kulland���m�z write() fonksiyonu gibidir. send() ile sokete veri g�nderiyoruz. Soket sunucu ile ba�lant�l� oldu�undan veri, sunucuya ula��r. Sunucu ise her send() iste�ine recv() ile kar��l�k verir. send() yada recv() i�lemleri her iki tarafta da yap�labilir. Sunucudan gelen her send() iste�ine kar�� da istemci de bir recv() vard�r. �rne�in ftp program�nda kar��l�k send() ve recv() i�lemleri vard�r. Siz �nce istemci taraf�ndan 'get dosya' komutunu g�ndererek dosya iste�inizi belirtiyorsunuz. Sunucu bu komutu okuyup yorumluyor ve size dosyay� ftp protokolune uygun paketler halinde g�nderiyor. Art�k siz okumaya ba�l�yorsunuz. Paketleri al�p birle�tirip yerel diske yaz�yorsunuz. Bu a�amadan sonra istedi�inizi yapt�rabilirsiniz.

istemci.c

// istemci.c - Stream soket istemci 
// Baris Simsek, <simsek at acikkod org>
// http://www.acikkod.org


#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>

#define PORT 3333

int main(int argc, char *argv[])
{
  struct hostent *h_name;
  struct sockaddr_in serv_addr;
  int sockfd;
  char buf[256];

  if(argc > 1) {
    h_name = gethostbyname(argv[1]);
  }
  else {
    printf("Kullanimi: %s hostname\\n",argv[0]);
    exit(1);
  }

  bzero((char *) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = *(u_long *) h_name->h_addr;
  serv_addr.sin_port = htons(PORT);
  printf("Sunucu adresi: %s\\n",inet_ntoa(serv_addr.sin_addr));

  if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("socket");
  if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) {
    perror("connect");
    exit(1);
  }

  printf("Mesajinizi girin: ");
  fgets(buf, sizeof(buf)+1, stdin);

  if((send(sockfd, buf, sizeof(buf), 0)) <= 0) perror("send");
  if((recv(sockfd, buf, sizeof(buf), 0)) <= 0) perror("recv");
  printf("Sunucu'dan gelen mesaj: %s", buf);

  shutdown(sockfd, 2);
  close(sockfd);

  return 0;
} 

6. Geli�mi� G/�

6.1. Bloksuz G/�

Giri�/��k�� (I/O); bir dosyaya, pipe'a, terminale veya a� ayg�t�na yazmak veya bu ayg�tlardan okumak gibi i�lemleri i�ermektedir.

Okunacak veri haz�r de�ilse veya yaz�lacak veri o an kabul edilmiyorsa bu i�lemleri yapan s�re�ler bloklanacakt�r. Bloksuz G/� (Nonblocking I/O), verinin veya ayg�t�n haz�r olmamas� gibi durumlarda bloklanmay� tamamen ortadan kald�ran bir �zelliktir. Bu konunun detaylar� d�k�man�n kapsam� d���ndad�r. (man 2 fcntl)

6.2. select()

Soket program ayn� anda birden fazla soketten veri okumak veya yazmak durumunda kalabilir. Bunu tek soket tan�mlay�c� ile sa�layamazs�n�z. ��nk� soketiniz blok durumuna ge�ti�inde (�rne�in accept(), ba�lant� gelene kadar program�n blok olmas�na neden olur) kodunuzun geri kalan k�sm� �al��maz, bloktan ��kmay� bekler.

��yle bir senaryoyu hayal edelim. �ki adet soket tan�mlay�c� var ve bu ikisi ile kar�� u�tan dosya veri alacaks�n�z. 1. u� hen�z veriyi haz�rlamad� ancak 2. u� haz�rlad� varsayal�m. E�er program 1. soket tan�mlay�c� ile ilk �nce 1. u�tan veri �ekmeye �al���rsa blok olacakt�r. 2. ucun verisi haz�r oldu�u halde veri al�namayacakt�r. Oysa select() ile bu iki u� kontrol edilip haz�r olan u�tan -senaryomuzda 2. u�- veri okunsa idi program blok olmayacak ve verisi haz�r olan i�lerini yapmaya devam edecekti. Bu �ekilde bloklanma riski ta��mayan bir program yaz�labilir.

Tek bir s�re� i�erisinde bloksuz G/� kullanarak bu sorun ��z�lebilir. B�t�n dosya tan�mlay�c�lar bloksuz G/� yapacak �ekilde set edilir. E�er veri haz�r de�ilse read() hemen sonlan�r. Ayn� i�lemi ikinci dosya tan�mlay�c�s� i�in de yapar�z. Belli bir s�re sonra tekrar ilk tan�mlay�c�y� kontrol ederiz. Buna 'polling' deniliyor. Bunun dezavantaj�, gereksiz yere CPU zaman� harcamaktad�r.

Ayn� problemi ��zmek i�in kullan�labilecek bir di�er teknik de "asenkron G/�". Bu y�ntemde, dosya tan�mlay�c�m�z G/� i�in haz�r oldu�unda �ekirdek, G/� yapacak s�reci haberdar edecektir. Ancak burada standart problemleri ve sinyalleri i�leme (signal handling) ile ilgili problemler vard�r.

Bunlardan daha iyi bir teknik ise G/� �o�ullama (I/IO multiplexing) olarak adland�r�lmaktad�r. �lgilendi�imiz tan�mlay�c�lar�n eklendi�i bir k�me vard�r ve tan�mlay�c�lardan biri G/� i�in haz�r olmad�k�a ��kmayan bir sistem �a�r�s� yap�l�r. Sistem �a�r�s�ndan ��k�ld���nda hangi tan�mlay�c�lar�n G/� i�in haz�r oldu�u sorulabilir.

select birden fazla soket tan�mlay�c�n�n durumunu takip eden ve BSD4.2 ile gelen bir sistem �a�r�s�d�r. Burada �unu belirtmeliyim ki, select() yaln�zca soketler i�in de�il genel olarak dosya ve G/� i�lemleri i�in kullan�lan bir sistem �a�r�s�d�r.

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct
timeval *timeout);

n: En b�y�k soket tan�mlay�c�n�n bir fazlas� (tan�mlay�c�lar 0'dan ba�lad���ndan)
readfds: Okumak i�in izlenecek (haz�r olup olmad��� bak�lacak) soket tan�mlay�c�
writefds: Yazmak i�in izlenecek soket tan�mlay�c�
exceptfds: �stisnai durumlar i�in izlenecek soket tan�mlay�c�

timeval, a�a��daki �ekilde bir veri yap�s�d�r:

struct timeval {
  long tv_sec; /* seconds */
  long tv_usec; /* microseconds */
};

timeout e�er NULL olarak verilirse bir dosya haz�r olana kadar blokda bekler. Haz�r olmazsa sonsuza kadar bekleyecektir. Tabi sinyal(signal) gonderilirse sonlan�r. E�er sinyal ile sonland�r�l�rsa select() -1 d�nd�recektir ve errno=EINTR olacakt�r.

'0' a setlenirse hi� beklemez. B�t�n belirtilen tan�mlay�c�lar test edilir ve �a�r�dan hemen ��k�l�r. Bu, select i�inde blocklanmadan birden fazla tan�mlay�c�y� test etmek i�in kullan�l�r.

0'dan b�y�k bir de�ere setlenirse o de�er kadar bekler. Belirtilen tan�mlay�c�lardan biri haz�r oldu�unda veya zamana��m�na u�rad���nda sistem �a�r�s� return yapar.

G�zetlenecek tan�mlay�c�lar tan�mlay�c� setine (descriptor set) eklenir. Tanimlay�c� seti, fd_set veri yap�s� �eklinde kay�t edilmi� veridir. fd_set, her tan�mlay�c� i�in bir bit tutar ve ge�erli boyutu 1024 bittir (sys/types.h i�inde tan�ml�). Set �zerinde i�lem yapmak i�in baz� makrolar tan�mlanm��t�r:

fd_set a�a��daki gibi tan�mlan�r:

fd_set dset;

Seti s�f�rlamak i�in:

FD_ZERO(&dset);

Takip etmek istedi�imiz tan�mlay�c�lar� eklemek i�in:

FD_SET(fd, &dset); 

select() seti de�i�tirmektedir. select sistem �a�r�s�ndan sonra bir tan�mlay�c�n�n hala sette olup olmad���n� test etmek i�in:

if (FD_ISSET(fd, &dset)) {
  ...

}

Bir tan�mlay�c�y� setten ��kartmak i�in:

FD_CLR(fd, &dset); 

Bu bilgiler �����nda bir uygulama geli�tirebiliriz. Standart giri� (stdin), dosya tan�mlay�c�s� 0 olan bir dosyad�r. E�er bir PC kullan�yorsan�z klavye standart giri�tir. A�a��daki kod, standart giri�i izlemektedir. E�er standart giri� okumak i�in haz�rsa (bunun anlam� klavyeden bir�ey yaz�p enter'a basm��sak) haz�r oldu�unu ekrana basacak. FD_ISSET ile de verinin haz�r oldu�unu g�rece�iz (Haz�r oldu�unda FD_ISSET, true olacakt�r. E�er haz�r de�ilse false olacakt�r.).

/*
 * select.c - I/O multiplexing
 *
 * Baris Simsek, <simsek at acikkod org>
 * http://www.acikkod.org
 * 07/07/2004
 *
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int
main(void) {
  fd_set dset;
  struct timeval tv;
  int ret;

  FD_ZERO(&dset);
  FD_SET(0, &dset); /* stdin'i gozlemeye aldik */
  tv.tv_sec = 10; /* 10 sn giris icin bekle */
  tv.tv_usec = 0;

  ret = select(1, &dset, NULL, NULL, &tv);

  if (ret == -1)
    perror("select()");
  else if (ret) {
    printf("Standart input okumak i�in hazir.\\n");
    if(FD_ISSET(0, &dset))
      printf("Standart input icin dset true\\n");
  }
  else {
    printf("10 saniye icinde standart giristen veri girilmedi.\\n");
    if(!FD_ISSET(0, &dset))
      printf("Standart input icin dset false\\n");
  }
  return 0;
}
 

7. S�k Sorulan Sorular

7.1. Kitap �nerebilir misiniz?

W. Richard Stevens'�n "UNIX Network Programming - Volume 1" kitab� bu alanda ba�l�ca referans kitapt�r.

7.2. Soketler Nas�l �al���r?

Soketler (�zelikle connection oriented soketler) dosyalar veya PIPE gibi �al���r. Pipe'dan fark� iki y�nl� olmas�d�r. Dosyalardan fark� ise bekledi�iniz kadar veri okuyamayabilir veya istedi�iniz kadar veri yazamayabilirsiniz.

7.3. select() veri haz�r dedi�i halde, 0 byte neden okunur?

select() verinin haz�r oldu�unu s�yledikten sonra kar�� taraf ba�lant�y� koparm��t�r. Bu da read() 'in 0 d�nd�rmesine neden olur.

7.4. Soket se�eneklerini nas�l de�i�tiririm?

int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);

int flag = 1;
int result = setsockopt(sock, /* socket affected */
                        IPPROTO_TCP, /* se�ene�i TCP seviyesinde set et. */
                        TCP_NODELAY, /* se�enek */
                        (char *) &flag,
                        sizeof(int)); /* se�enek de�erinin b�y�kl��� */

Se�enekler hakk�nda detay i�in "man 2 setsockopt"

7.5. SO_KEEPALIVE se�ene�i neden kullan�l�r?

Oturum a�m�� iki bilgisayar aras�nda belli bir s�re (RFC1122 de 2 saat olarak tan�mland�) veri al��veri�i olmazsa, kar�� taraf� yoklamak i�in (ACK isteyerek) kullan�l�r. Zira kar�� taraf ula��lamaz durumda olabilir. Bu durumu alg�lamak i�in kullan�l�r.

7.6. Soketi tam olarak nas�l kapat�r�m?

Soket kapat�lt�ktan sonra "netstat -na" ile bak�ld���nda sisteminizde TIME_WAIT'de duran soketler hala g�z�kebilir. Bu normaldir. ��nk� TCP, b�t�n verinin kar��l�kl� transfer edildi�inden emin olmak istiyor. Soket kapat�ld���nda her iki taraf da ba�ka veri transferi olmayaca�� konusunda anla�m�� demektir. B�yle bir anla�madan sonra socket rahatl�kla kapat�labilir. Ancak burada iki problem s�zkonusu olacak. Bunlardan biri son ACK'in ula��p ula�mad��� bilinemeyecek. (Bu ACK i�in tekrar ACK istense bunun da ula��p ula�mad��� belli olmayacak. K�s�r d�ng� olur.). E�er bu ACK a�da kaybolmu� ise sunucu bunu bekliyor olacakt�r. Bir di�er problem de e�er bir paket router'in birinde herhangi bir nedenle bekliyorsa ve al�c� taraf bunu belli bir s�re i�erisinde alamam��sa paketi yeniden talep edecektir. Ancak di�er paket ger�ekte kaybolmam��t�r ve belli bir s�re a�da yeniden ortaya ��kacakt�r. Bu kaybolma ve yeniden ortaya ��kmas� s�resi i�erisinde ba�lant� koparsa ve ayn� host ayn� porttan yeni bir ba�lant� a�arsa g�nderece�i paketin s�ra numaras� a�daki ile �st �ste binecektir. ��nk� eski oturumdan kalma bir paket yeni oturumda transfer edilmi�tir. Bundan kurtulmak i�in TIME_WAIT durumu ortadan kalkmadan yeni bir oturum a�mamal�.

B�t�n bunlar d���n�ld���nde TIME_WAIT'in programc� i�in bir yard�mc� oldu�u anla��l�r. Ancak TIME_WAIT oldu�u s�rece program�n�z ayn� soketi yeniden bind() edemeyecektir. 7.4. anlat�ld��� �ekilde SO_REUSEADDR se�ene�i set edilerek bu sorunu ��zebilirsiniz. �te yandan TIME_WAIT'te bekleyen soketler bir s�re sonra (Linux'lerde bu 60 sn.dir.) close() olacakt�r. sysctl ile bu s�re de�i�tirilebilir.

close() do�ru kapatma y�ntemi ise de shutdown() daha kullan��l�d�r. ��nk� tek y�nl� soketi kapama olana�� da sunar.

int shutdown(int s, int how);

�kinci parametre ile kapa y�n�n� verebilirsiniz:

SHUT_RD: Veri al�m� kesilecektir.
SHUT_WR: Veri g�nderimi kapat�lacakt�r.
SHUT_RDWR: �ki y�nl� veri al��veri�i durdurulacakt�r. (close)

close(), o s�re� i�in soketi kapat�r ancak e�er socketi ba�ka bir s�re�le payla��yorsa socket hala a��k duracakt�r. shutdown() b�t�n s�re�ler i�in soketi kapat�r.

7.7. String halindeki bir adresi internet adresine nas�l �evirim?

struct in_addr *atoaddr(char *address) {
  struct hostent *host;
  static struct in_addr saddr;

  /* �nce IP format�nda deniyoruz. */
  saddr.s_addr = inet_addr(address);
  if (saddr.s_addr != -1) {
    return &saddr;
  }

  /* IP format�nda de�ilse FQDN olarak deniyoruz. */
  host = gethostbyname(address);
  if (host != NULL) {
    return (struct in_addr *) *host->h_addr_list;
  }
  return NULL;
}

7.8. Soketlerde dinamik buffer kullanman�n bir yolu var m�?

Soketten okuyaca��n�z veri miktar� belli olmad���nda b�yle bir ihtiya� do�uyor. Bu durumda malloc() ile m�mk�n olan en b�y�k tampon belle�i ay�r�rs�n�z. Okunan verinin b�y�kl���ne g�re tampon bellek realloc() ile yeniden boyutland�r�l�r. Zaten pek �ok UNIX'de malloc() fiziksel bellekten yer ay�rmaz. Sadece adres uzay�n� belirler. Tampona veri yazd���n�zda ger�ek bellek sayfalar� kullan�l�r. Bu nedenle b�y�k buffer ay�rmakla gereksiz kaynak kullan�m�na neden olunmaz.

7.9. "address already in use" hatas�n� neden al�r�m?

Port kullan�l�yordur veya sunucu bir program� hen�z sonland�rd�n�z ve socket TIME_WAIT'dedir. �kinci durum i�in 7.4. ve 7.5. sorular�n�n ��z�mlerine bak�n�z. Birinci durum i�in ayn� portta �al��an di�er socket program� durdurman�z gerekmektedir.

7.10. Program�m� nas�l daemon yapabilirim?

En kolay yolu inetd ile kullanman�zd�r. Di�er bir y�ntem ise fork() ederek isteklere cevap vermekdir. Detay icin http://www.enderunix.org/docs/daemontr.html Programin temel iskeleti asagidaki yapiya cevirilmeli:

ret = fork ();
if (ret == -1) { /* fork hata verdi */
  perror ("fork()");
  exit (3);
}
if (ret > 0) exit(0); /* Ana s�re� ��kar */
if (ret == 0) { /* Alt s�re� devam eder */
  close (STDIN_FILENO);
  close (STDOUT_FILENO);
  close (STDERR_FILENO);
  if (setsid () == -1)  exit(1);
  /* Alt s�rece ait i�ler */
}

7.11. Ayn� anda birden fazla soketi nas�l dinlerim?

select() kullan�n. Hangi socket veri i�in haz�r ise onun, kullanman�za olanak sa�lar. 6.2. select() b�l�m�ne bak�n�z.

7.12. 1024 ten k���k portlar� neden bind edemiyorum?

G�venlik nedenleri ile 1024'ten k���k portlar� yaln�zca yetkili kullan�c� (root) a�abilir.

8. Belge Tarih�esi

VI.s�r�mde "7. S�k Sorulan Sorular" b�l�m� eklendi. (1 A�ustos 2004)

V.s�r�mde Soket T�rleri ve Veri D�n���mleri ba�l�klar� eklendi. Sarmalama(Encapsulation) tan�m� eklendi. (8 Temmuz 2004)

IV.s�r�mde Geli�mi� G/� ba�l��� eklendi. (28 Haziran 2004)

III.s�r�mde RFC'ler g�zden ge�irilerek yeniden d�zenlenmi�tir. �lk s�r�mlerdeki baz� yanl��lar giderildi. (5 Haziran 2004)

II.s�r�m, Linux Kullan�c�lar� Derne�i Liste �yeleri i�in yeniden g�zden ge�irildi. (2001)

�lk s�r�m: 10 Kas�m 1998 (KT� Bilgisayar Klub� Dergisi i�in yaz�ld�.)

Hatalar� �ekinmeden bana bildirebilirsiniz. b$