Nəqliyyat xidməti

== Berkeley soketləri ==

Soketlər ilk əvvəl 1983 də Berkeley UNİX 4.2 BSD program paylayıcısının bir parçası olaraq tanıdıldı. Onlar tez bir zamanda populyar oldular. Primitivlər hal-hazırda bir çox əməliyyat sistemləri tərəfindən özəlliklə UNİX əsaslı sistemlərdə internet proqramlaşdırma üçün ən çox istifadə olunandır və Windows üçün “winsock” adlı bir soket tərzi API vardır.

Şəkil1

Primitivlər Şəkil 2 də listlənmişdir. Kobudca desək, ilk misalımızın modelini təqib edirlər ancaq daha çox özəllik və çeviklik verir.

Şəkil 2 TCP üçün soket primitivləri
Primitiv Mənası
SOCKET Yeni bir əlaqə son nöqtəsi yaradır.
BIND Lokal bir adresi bir soketlə əlaqələndirin.
LISTEN Əlaqələri qəbul etmə istəyini elan edir; sıra ölçüsü ver
ACCEPT Gələn əlaqəni passiv olaraq qurur
CONNECT Aktiv olaraq bir əlaqə qurmağa çalışır
SEND Əlaqə üzərindən bəzi məlumatlar göndərir
RECEIVE Əlaqədən bəzi məlumatlar qəbul edir
CLOSE Əlaqəni azad edir

Cədvəldəki ilk dörd primitiv sırayla serverlər tərəfindən icra olunur. SOCKET primitiv obyekti yeni son nöqtə yaradır və onun üçün daşıma obyektinin içində cədvəl sahəsi ayırır. Çağırış parametrləri istifadə olunacaq adresləmə formatını, arzulanan servis növünü (məs, güvənilir bayt axışı) və protokolu müəyyən edir. Müvəffəqiyətli bir SOCKET çağırışı bir fayldakı OPEN çağırışı kimi müvəffəqiyyətli çağırılışlarda istifadə olunacaq adi bir fayl deskriptoru geri qaytarır.

Yeni yaradılan soketlərin şəbəkə adresləri yoxdur. Bunlar BIND primitivini istifadə edərək təyin edilir. Bir server bir adresi bir soketə bağladıqdan sonra, uzaqdakı klentlər ona qoşula bilər. SOCKET çağrısının bibaşa bir adres yaratmasını istəməməsinin səbəbi, bəzi prosesslərin adreslərini önəmsədiyi(digər bir deyişlə illərcə eyni adresi istifadə etmələri və hərkəsin bu adresi bilməsidir) digərlərinin isə etmədiyi bir vəziyyətdir.

Sonrasında bir neçə klentin eyni zamanda qoşulmağa cəhd etməsi vəziyyətində gələn çağrışları sıraya alan LİSTEN çağrışıdır. İlk misalımızda LİSTEN-ın əksinə, soket modelində LİSTEN bir bloklama çağırışı deyil. Gələn bir qoşulmanı gözləməkdən əl çəkmək üçün server ACCEPT primitivini icra edir. Qoşulma istəyən bir bölüm gəldiyində, daşıma obyekti orjinalıyla eyni özəlliklərə sahib yeni bir soket yaradır və bunun üçün bir fayl deskriptor qaytarır. Server daha sonra yeni soketdəki qoşulmanı icra etmək və orjinal soketdəki bir sonrakı qoşulmanı gözləmək üzərə geri qayıtmaq eçen bir prosesi və ya tredi çıxarda bilər. ACCEPT fayllar üçün olduğu kimi standart bir şəkildə oxuma və yazma üçün istifadə olna bilən bir fayl deskriptoru qaytarır. İndi müştəri tərəfinə baxaq. Burada da ilk əvvəl bir soket SOCKET primitiv istifadə edilərək yaradılmalıdır, amma istifadə olunan adres server üçün önəmli olmadığından BIND lazımlı deyildir. CONNECT çağırışçını

 Blokluyur və əlaqə prosesini aktiv başladır. Proses tamamlandıqda klent  prosesi əngəli qalxır və əlaqə qurulur. Artıq hər iki tərəf də , full-duplex əlaqə üzərindən məlumat göndərmək və almaq üçün SEND və RECEİVE özəlliyini istifadə ediləbilər. Standart UNIX READ və WRITE sistem çağırışları, SEN və RECEİVE özəl seçənəklərindən heçbirinin lazım olmaması vəziyyətində istifadə edilə bilər.Soketlərlə əlaqə sərbəst buraxılması simmetrikdir. Hər iki tərəf bir CLOSE primitivini icra olunduqda, əlaqə sərbəst qalır.Soket API-sinin gücü bir proqram tərəfindən digər daşıma xidmətləri üçün istifadə edilə bilər. Məsələn soketlər əlaqəsiz bir daşıma xidməti ilə istifadə oluna bilər.

Soket API-nin gücü bir proqram tərəfindən digər daşıma xidmətləri üçün istifadə oluna bilər. Məsələn soketlər əlaqəsiz bir daşıma xidməti ilə istifadə edilə bilər. Bu vəziyyətdə CONNECT uzaq daşıma cütünün adresini quraşdırar və SEND və RECEİVE uzaq cütdən gələn və uzaqdakı cütlərdən dataqramları göndərib almağa yarıyır. Soketlər həmçinin , bir bayt axışı yerinə məlumat axışı təchiz edən və tıxanıqlıq idarəsi olan və ya olmayan bir daşıma protokolları ilə istifadə edilə bilər. Məsələn DCCP(Datagram Congestion Controlled Protocol) tıxanıqlıq idarəsi olan UDP versiyasıdır. Bununla birlikdə soketlər daşıma interfeysi üzərindəki son sözü olmayacaqdır. Məsələn proqramlar əsasən eyni serverdən bir neçə obyekt istəyən Web brauzer kimi bir qrup əlaqəli axınla işləyir. Soketlərlə ən təbii uyumu aplikasiya proqramları üçün obyekt başına bir axın istifadə olunmasıdır. Bu struktur tıxanıqlıq kontrolu, hər bir axın üçün ayrı olaraq tətbiq olunması mənasına gəlir, qrup arasında deyil. Əlaqəli protokol qruplarını aplikasiya üçün daha effektiv və bəsit bir şəkildə dəstəkləyən daha yeni protokollar və interfeyslər dizayn edilmişdir.İki misal, RFC 4960 və SST(Struklaşdırılmış Axın Daşıması)-da elan edilən SCTP (Axın İdarəsini Daşıma Protokolu) –dir. Bu protokollar əlaqəli axın qruplarının üstünlüklərini əldə etmək üçün soket API-nı biraz dəyişdirilməlidir və həmçinin əlaqə yönlü və əlaqəsiz trafikin və hətta birdən çox şəbəkə yolunun bir qarışığı kimi özəllikləri dəstəkləyir. Müvəffəqiyyətli olub olmadıqlarını zaman göstərəcək. 

Soket proqramlamaya bir misal: İnternet Fayl Serveri[redaktə | mənbəni redaktə et]

Şəkil 1 də real soket çağırışını yerinə yetirən klent və server kodunu gözdən keçirək. Burada çox primitiv bir internet fayl serverinin yanında bunu istifadə edən bir klent var.Kodun bir çox limitləri vardır,ancaq prinsib olaraq server kodu internetlə əlaqəli hərhansı bir UNİX ƏS-də kompaylr edilə bilər və işlədilə bilər.

Klient kodu dünyanın hərhansı bir UNİX maşınında kompaylr edilib işlədilə bilər. Klient kodu serverin maşından əlçatımı olan hər hansı bir faylı almaq üçün uyğun parametrlərlə icra edilə bilir. Fayl təbii ki, bir fayla yönləndirilə bilər.Əvvəlcə serverin koduna baxaq. Bəzi standart başlıqları əlavə edərək başlayır, bunların son 3 ü internet ilə əlaqəli təməl elanları və verilənlərin strukturunu saxlayır. Sonrasında SERVER PORT-un 12345 olaraq elan edilməsi gəlir. Bu rəqəm təxmini seçildi. 1024-65535 arasındakı hərhansı portu başqa proseslər tərəfindən istifadə edilmirsə, götürmək olar. 1023 den aşağı portlar isə üstünlük təşkil edir. Serverdəki sonrakı iki sətr lazım olan 2 sabiti təyin edir. İlki fayl transferi üçün istifadə olunan bayt cinsindən ölçünü bildirir.İkincisi varışda əlavə olanları atılmadan neçə gözləyən əlaqənin ediləbiləcəyini təyin edir.

Klient kodu[redaktə | mənbəni redaktə et]

/*Bu səhifə server proqramından bir fayl istəyəbiləcək bir klient proqramı saxlayır.
bir sonrakı səhifədə. Server bütün faylı göndərərək cavab verir. */
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h> 
#include <netdb.h>
#define SERVER PORT 12345	 /* təqribi, ancaq klient və server qəbul edilməli. */
#define BUF SIZE 4096 		/* blok transfer ölçüsü.*/
int main(int argc, char **argv)
{
int c, s, bytes; char buf[BUF SIZE]; 	/* gələn fayl üçün bufer  */ 
struct hostent *h; 				/* server haqqında məlumat*/ 
struct sockaddr in channel; 		/* İP adresləri saxlayır. */ 

if (argc != 3) fatal("Usage: client server-name file-name"); 
h = gethostbyname(argv[1]); 		/* hostun İP adresini axtarır. */ 
if (!h) fatal("gethostbyname failed"); 
s = socket(PF INET, SOCK STREAM, IPPROTO TCP);
if (s <0) fatal("socket"); 
memset(&channel, 0, sizeof(channel)); 
channel.sin family= AF INET; 
memcpy(&channel.sin addr.s addr, h->h addr, h->h length); 
channel.sin port= htons(SERVER PORT);

c = connect(s, (struct sockaddr *) &channel, sizeof(channel)); 
if (c < 0) fatal("connect failed");
 /* Əlaqə yaradıldı. Sonuda 0 bayt olan fayl adı göndərildi. */ 
write(s, argv[2], strlen(argv[2])+1); 
/* Faylı alıb standart çıxışa ver. */
 while (1) {
 bytes = read(s, buf, BUF SIZE); 		/* soketdən oxu.*/ 
if (bytes <= 0) exit(0); 			/* faylın sonuna bax .*/ 
write(1, buf, bytes); 			/*standart çıxışa yaz. */ }
}
fatal(char *string)
 {
 printf("%s\n", string);
 exit(1);
 }

Server kodu [redaktə | mənbəni redaktə et]

#include <sys/types.h> 		/* Server kodudur. */
#include <sys/fcntl.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#define SERVER PORT 12345		 /* təqribi, amma klient və sever razı olmalıdır.*/ 
#define BUF SIZE 4096 			/* blok transfer ölçüsü */ 
#define QUEUE SIZE 10 
int main(int argc, char *argv[]) 
{ 
int s, b, l, fd, sa, bytes, on = 1; 
char buf[BUF SIZE]; 			/* gedən fayl üçün bufer */ 
struct sockaddr in channel;		 /* İP adresləri saxlayır. */
 /* Soketə qoşulmaq üçün adres strukturu yaradır. */ 
memset(&channel, 0, sizeof(channel)); 	/* 0 kanalı */
channel.sin family = AF INET; 
channel.sin addr.s addr = htonl(INADDR ANY); 
channel.sin port = htons(SERVER PORT);	 
/* Passiv açılma . Əlaqəni gözləyir. */ 
s = socket(AF INET, SOCK STREAM, IPPROTO TCP); 		/* soket yaradır. */ 
if (s < 0) fatal("socket failed"); 
setsockopt(s, SOL SOCKET, SO REUSEADDR, (char *) &on, sizeof(on)); 

b = bind(s, (struct sockaddr *) &channel, sizeof(channel)); 
if (b < 0) fatal("bind failed"); 
l = listen(s, QUEUE SIZE);					/* sıranın ölçüsünü müəyyən edir. */ 
if (l < 0) fatal("listen failed"); 
/* Soket artıq quraşdırılıb və qoşuludur. Əlaqəni gözləyin və icra edin. */ 
while (1) { 
sa = accept(s, 0, 0);		 /* Qoşulma istəkləri üçün blok. */ 
if (sa < 0) fatal("accept failed"); 
read(sa, buf, BUF SIZE);		 /* Soketdən fayl adını oxuyur. */ 
/* Faylı alıb geri gətirir. */ 
fd = open(buf, O RDONLY); 	/* göndəriləcək faylı geri aç. */ 
if (fd < 0) fatal("open failed"); 
while (1) { 
bytes = read(fd, buf, BUF SIZE); 		/* fayldan oxu */ 
if (bytes <= 0) break; 		/* faylın sonuna bax .*/ 
write(sa, buf, bytes); 		/* baytları soketə yaz. */ 
} 
close(fd); 		/* faylı bağla */ 
close(sa);		 /* əlaqəni kəs. */
 } 
}

Lokal dəyişənləri elan etdikdən sonra server kodu başlayır. Serverin İP adresini tutacaq bir verilənlər strukturu inisial edərək başlayır.Bu verilənlər strukturu serverin soketinə qoşulacaq. Memset çağırışı verilənlər strukturunu  0 a quraşdırır. Bunu təqib edən üç təyinat sahələrindən üçünü doldurur. Bunların sonuncusu, serverin portunu saxlayır. Daha sonra server bir soket yaradır və səhvləri yoxlayır (s<0 ilə göstərilir). Setsockopt çağırışı serverin fasiləsiz işləyəbilməsi üçün prtun təkrar istifadə edilməsinə icazə verməsi üçün lazımdır.İndi İP adresi soketə qoşulub və qoşulma çağırışının müvəffəqiyətli olub-olmadığını görmək üçün yoxlama reallaşdırılır.İnisializasiyanın son addımı serverin gələn çağırışları qəbul etmə istəyini elan etmək və server hələ də mövcud olanı işləyərkən yeni istəklərin gəlməsi vəziyyətində sistemə QUEUE SİZE qədər tutukmasını demək üçün listen çağırışı istifadə olunur. Sıra doludursa və əlavə istək gələrsə, bunlar atılır.

Bu nöqtədə serverə əsas dövrə girir. Onu saxlamanın tək yolu xaricdən məhv  etməkdir. Accept bloku bəzi klientlər onunla əlaqə yaratmağa çalışana qədər serveri əngəlləyir. Accept çağırışı müvəffəqiyətli olarsa, o oxuma yazma üçün istifadə olunan soket deskriptoru qaytarır.Əlaqə yaradıldıqdan sonra server fayl adını oxuyur. Əgər ad hələ möcud deyilsə, server blokları  onu gözləyir. Fayl adını aldıqdan sonra server faylı açar və dövrü olaraq fayldan blokları oxuyur və bütün fayl kopyalanana qədər soketə yazan bir dövrə girər.Daha sonra server fayl və əlaqəni bağlayır və bir sonrakı əlaqənin göstərilməsini gözləyir. Bu dövrü sonsuza qədər dəvam edir.

İndi isə klient koduna baxaq. Necə işlədiyini anlamaq üçün necə çağrıldığını bilmək lazımdır. Bunu client deyə çağıraq:

client flits.cs.vu.nl /usr/tom/filename >f

Bu çağırış ancaq server flits.cs.vu.nl –də işləyirsə və /usr/tom/filename faylı varsa və server ona oxuma keçidi verirsə ,işləyir. Çağırış müvəffəqiyyətli olarsa, fayl internet üzərindən transfer olunur və f-ə yazılır və arxasından klient programı çıxır. Server bir transferdən sonra dəvam etdiyindən, klient başqa faylları almaq üçün təkrar təkrar başlaya bilər. Klient kodu bəzi əlavələr və mənimsəmələrlə başlayır. İcra etmə düzgün sayda arqumentlə çağrılmış olub olmadığını yoxlayaraq başlayır(argc=3 proqramın adı üstəgəl iki arqument ). Argv[1] serverin adını saxlayır və gethostbyname tərəfindən bir İP adresinə çevrildiyini yaddan çıxarmayın. Bu funksiya adı axtarmaq üçün DNS istifadə edir.

Daha sonra bir soket yaradılır və inisializasiya olunur. Bundan sonra klient connect istifadə edərək serverə bir TCP əlaqəsi qurmağa çalışır. Server adlandırılmış maşında işləyirsə və SERVER_PORT-a qoşuludursa və boşda ya da listen sırasında yer varsa, əlaqə qurulacaqdır. Əlaqəni istifadə edərək klient soketin üzərinə yazaraq faylın adını göndərir. Göndərilən bayt sayı ada son verilən 0 baytın serverə adının harada sona çatdığını bildirməsi üçün göndərilməsi lazım gəldiyindən, düzgün adın birindən daha böyükdür. İndi isə klient dövrə girir, faylı soketdən blok-blok oxuyaraq standart çıxışa kopyalayır. Bittikdə, sadəcə çıxır. Fatal proseduru bir xəta mesajı çap edir və çıxır. Server və klient ayrı-ayrı kompaylr edildiyindən və normalda fərqli kompüterlərdə işlədiyi üçün fatal kodunu paylaşmazlar.

Xarici keçidlər[redaktə | mənbəni redaktə et]

Computer Networks, 5th Edition, paraqraf 6.1.3-6.1.4 səh 500-507