/*
* 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
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.
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.
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.
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.
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.
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() | ---------------------------------------------------------------------------
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�.
�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.
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");
�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.
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);
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.
// 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.
�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); } }
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));
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.
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 - 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; }
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)
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.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.
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$