Bu makalenin farklı dillerde bulunduğu adresler: English Castellano Deutsch Francais Nederlands Russian Turkce Arabic |
tarafından Angel Lopez Yazar hakkında: Angel Bilgisayar Mühendisliği mezunu.Şu anda öğretmen olarak Sun Microsystems'de çalışıyor, Solaris ve ağ yönetimi konularını anlatıyor. Son günlerde yardımcı yazar olarak Internet protokolleri konusunda Ra-Ma ile çalışıyor.Tasarlanması ve Unix sistemlerine uyarlanması üzerine.. İlgi duyduğu konuların başında ağ, güvenlik, sistem/ağ unix programlama ve son zamanlarda Linux çekirdeğini kırmak gibi konular uykularını azaltıyor. ;) İçerik: |
Özet:
Bu yazıda TCP/IP ağları üzerine multicast teknolojilerine giriş yapılıyor. Multicast iletişimlerinin teorisi ve multicast programlama için kullanacağımız Linux API detayları üzerinde duruluyor. Çekirdek fonksiyonlarının bu teknolojiye nasıl uyarlandığı gösteriliyor ve genel anlamda Linux altında multicast desteği gözden geçiriliyor. Yazı bir multicast uygulamasının gösterildiği çok basit bir C soket programıyla bitiyor.
Ağ üzerinden bir yere erişmek (bir arayüz ile) istediğinizde üç çeşit adres kullanabilirsiniz:
Bilgi dönücü, tek bir birim değilse ve çok fazla broadcast oluşturmak istemiyorsak Multicast addresleri çok kullanışlıdır. Özellikle çoğulortam bileşenlerinin(gerçekzamanlı ses ya da video gibi) yoğun kullanıldığı ağ ortamlarında bu durum sözkonusu olacaktır. Bant genişliğini düşündüğümüzde çoğul ortam verileri için unicast en iyi çözüm olmayacaktır.İstemcilerden herhangi biri yerel subnet dışında olduğu sürece broadcast da bir çözüm olmayacaktır.
Büyük olasılıkla bildiğiniz gibi , IP adresleri uzayı 3 sınıfta gruplanır. .A, B ve C adres sınıfı.Burada dördüncü sınıf olan (D) multicast adresleri için ayrılır. D sınıfına IPv4 adresleri 224.0.0.0 ve 239.255.255.255 uygundur.
IP adreslerinin en önemli 4 biti 224 ile 239 arasında değerler içeririr.
Diğer 28 bit, daha az önemli olan multicast grupları için ayrılır, aşağıda görüldüğü gibi :
Ağ düzeyinde IPv4 multicast adresleri üzerinde çalışılan ağ çeşidinin fiziksel adresleri üzerine haritalanmalıdır.Eğer unicast ağ adresleri ile çalışıyorsak,ARP protokolü kullanan birleşik fiziksel adresleri getirmeliyiz. Multicast adreslerinde ARP kullanılamaz. Bu nedenle fiziksel adresler başka bir yolla alınmalıdır. Burada bu haritlama yöntemiyle ilgili bazı RFC dokumanları bulunuyor:
Burada bazı multicast IPv4 adresleri bulunuyor:
Aşağıdaki tablo her adres aralığı için kullanılan isimlerle ve kendi birleşik TTL'leri (IP paketindeki canlı zaman sayacı) ile tüm multicast adres uzayını gösteriyor. Multicast IPv4'ün altında , TTL iki anlama geliyor. Okuyucuların büyük olasılıkla bildiği üzere, yanlış yapılandırılmış router tablolarının bulunduğu ağlarda sonsuz döngüleri engellemek için datagram'ların yaşam-zaman'larını kontrol eder. Multicast ile çalışır, üstelik datagram'a TTL değeri tanımlanmasına olanak tanır.i. e., ağdaki yolculuk ne kadar uzak olacaktır...Bu durum datagram kategorisi üzerine tanımlamaya olanak sağlar.
Scope | align=CENTER>TTL | Adres aralığı<</TD> | Açıklama |
Node | 0 | Datagram yerel konağa sınırlıdır. Herhangi bir ağ arayüzüne erişemeyecektir. | |
Link | 1 | 224.0.0.0 - 224.0.0.255 | Datagram gönderici konak subnet'ine sınırlandırılacaktır ve router'ın ötesinde bir işlem yapamayacaktır. |
Department | < 32 | 239.255.0.0 - 239.255.255.255 | Organizasyonun bir bölümü sınırlandırılmıştır. |
Organization | < 64 | 239.192.0.0 - 239.195.255.255 | Özel organizasyonlar için sınırlandırılmıştır. |
Global | < 255 | 224.0.1.0 - 238.255.255.255 | Herhangi bir sınırlama olmayan genel uygulamalar. |
LAN içinde, konak üzerindeki ağ arayüzü hedef durumundaki konağa gitmek
için gereksinimi olan tüm paketleri alt katmanlara gönderecektir. Bu paket
hedef nerdeyse orada olacaktır.(fiziksel ya da broadcast olabilir).
Eğer konak bir multicast gruba üye ise, ağ arayüzü bu gruba hedeflenmiş
paketleri tanıyacaktır: tüm bu hedef adresler üye olduğu multicast
gruplarla eşleşecektir.
Bu nedenle,eğer fiziksel adresi: 0:C0:F6:A0:4A:B1 ve 224.0.1.10 multicast grubuna üye ise, uygun paketler bir sonraki hedef adresten uygun olanına yönelecektir:
Üstelik router'lar 224.0.0.1 grubuna IGMP mesajları gondererek her konak ile ilgli grup bilgisini yanıtlayacaktır. Konak, istemini yaptıktan sonra sayacı kendi değerine alacaktır ve sayaç sıfırlandığında yanıtlayacaktır. Bu tüm konakların aynı zamanda yanıt vermesini dolayısıyla ağ üzerine aşırı yüklemeyi engelleyecektir. Konak yanıtladığında grubun multicast adreslerine mesaj gönderecektir.Grup üyesi tüm diğer konaklar yanıtı görecektir ve kendileri yanıtlamayacaktır, onaylayan bir konak, subnet router'in bu gruba multicast mesaj göndermesine yeterlidir.
Eğer tüm konaklar onayladıysa hiç biri yanıtlamayacaktır ve router bu grupta hiç bir konağın ilgisini çekmediğine karar verecektir ve subnet'e giren uyumlu mesajların routing işlemini sonlandıracaktır. Diğer seçenek IGMPv2 ile uyarlanmış ,konaktan geri gelen sinyal iletişimi 224.0.0.2 grubuna mesaj gönderir.
Bir önceki deneyim ile soket programlamada okuyucu yalnızca beş yeni multicast arama seçeneği bulacaktır. Fonksiyonlar setsockopt() ve getsockopt() tanıtmak ya da bu beş seçeneğin değerlerini okumak için kullanılacaktır.Tablo kendi yönetsel veri çeşitleri ve açıklamalarla multicast için sağlanan değerleri gösteriyor:
IPv4 Seçeneği | Veri Çeşidi | Açıklama |
IP_ADD_MEMBERSHIP | struct ip_mreq | Multicast gruba üye olma. |
IP_DROP_MEMBERSHIP | struct ip_mreq | Multicast grubundan çekilmek. |
IP_MULTICAST_IF | struct ip_mreq | struct ip_mreq multicast mesajların uyumu için özel arayüzler. |
IP_MULTICAST_TTL | u_char | multicast mesajların uyumu için özel TTL. |
IP_MULTICAST_LOOP | u_char | Aktif olan ya da olmayan tekrarlı multicast mesajları. |
The ip_mreq yapısı başlık dosyasında tanımlanır , <linux/in.h> aşağıda gösterildiği gibi:
struct ip_mreq { struct in_addr imr_multiaddr; /* Grubun IP multicast adresleri */ struct in_addr imr_interface; /* Arayüzün yerel IP adresleri */ };ve multicast seçenekleri:
#define IP_MULTICAST_IF 32 #define IP_MULTICAST_TTL 33 #define IP_MULTICAST_LOOP 34 #define IP_ADD_MEMBERSHIP 35 #define IP_DROP_MEMBERSHIP 36
Multicast gruba üyelik olabildiğinde bu seçeneği soket üzerine setsockopt() fonksiyonu ile gönderir. ip_mreq parametresi yapıdır.İlk yapı alanı, imr_multiaddr , üye olmak istediğimiz multicast adresleri içerir. İkinci alan , imr_interface , kullanacağımız arayüzün IPv4 adreslerini içerir.
Bu seçeneği kullanarak işlem multicast grubundan çıkarılabilir. ip_mreq alan yapısı bir önceki konudakine benzer şekilde kullanılır.
Bu seçenek multicast mesajını gönderecek soket olan ağ arayüzünü belirlemede kullanılır. Arayüz ip_mreq içinde bir önceki konudaki gibi verilecektir.
Datagramlar ile soket kullanan multicast mesajları için TTL (Time To Live) kullanılır. .Kendi değeri 1'dir ,bu datagram'ın yerel subnet'in ötesine geçmeyeceği anlamına gelir.
İşlem multicast grubu için mesaj gönderdiğinde eğer arayüz gruba üye ise alınır. Eğer bu kaynak ağ içerisinde herhangi bir yer ise aynı yolla alınacaktır. Bu seçenek bu davranışın aktif olmasını ya da aktif olmamasını sağlar.
Nerede multicast gruba mesaj gönderen bir işlem varsa ve bazı işlemler mesajları yanıtlayan gruba aktarılıyorsa ,bunlar ekranda gösteriliyor.
Bir sonraki kod uyarlaması sunucunun multicast grup 224.0.1.1 'e tüm
standart girişleri iletmesi ile ilgili. Görebildiğiniz gibi multicast gruba
mesaj göndermek için herhangi özel bir harakete gerek yok. Hedef grup
adresleri yeterli.
Loopback and TTL değiştirilebildi, eğer kendi değerleri uygulama için uygun
değilse.
Standard giriş multicast grup 224.0.1.1 'e gönderiliyor.
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #define MAXBUF 256 #define PUERTO 5000 #define GRUPO "224.0.1.1" int main(void) { int s; struct sockaddr_in srv; char buf[MAXBUF]; bzero(&srv, sizeof(srv)); srv.sin_family = AF_INET; srv.sin_port = htons(PUERTO); if (inet_aton(GRUPO, &srv.sin_addr) < 0) { perror("inet_aton"); return 1; } if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return 1; } while (fgets(buf, MAXBUF, stdin)) { if (sendto(s, buf, strlen(buf), 0, (struct sockaddr *)&srv, sizeof(srv)) < 0) { perror("recvfrom"); } else { fprintf(stdout, "Enviado a %s: %s\n", GRUPO, buf); } } }
Aşağıda sunucu tarafından onaylanan multicast grup bilgisi istemci tarafının kodu görülüyor.Alınan mesajlar standart çıkış üzerinde görünüyor. Bu özellik kodun IP_ADD_MEMBERSHIP seçeneniyle sağlanır. Kalan kod UDP mesajlarını alma gereksinimi olan standart işlemler için.
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #define MAXBUF 256 #define PUERTO 5000 #define GRUPO "224.0.1.1" int main(void) { int s, n, r; struct sockaddr_in srv, cli; struct ip_mreq mreq; char buf[MAXBUF]; bzero(&srv, sizeof(srv)); srv.sin_family = AF_INET; srv.sin_port = htons(PUERTO); if (inet_aton(GRUPO, &srv.sin_addr) < 0) { perror("inet_aton"); return 1; } if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return 1; } if (bind(s, (struct sockaddr *)&srv, sizeof(srv)) < 0) { perror("bind"); return 1; } if (inet_aton(GRUPO, &mreq.imr_multiaddr) < 0) { perror("inet_aton"); return 1; } mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) { perror("setsockopt"); return 1; } n = sizeof(cli); while (1) { if ((r = recvfrom(s, buf, MAXBUF, 0, (struct sockaddr *) &cli, &n)) < 0) { perror("recvfrom"); } else { buf[r] = 0; fprintf(stdout, "Mensaje desde %s: %s\n", inet_ntoa(cli.sin_addr), buf); } } }
İşlem multicast gruba bağlanmak istediğinde setsockopt fonksiyonu kullanılarak IP düzeyinde IP_ADD_MEMBERSHIP seçeneğine kurar. Bu fonksiyon için gerçek bir uyarlama /usr/src/linux/net/ipv4/ip_sockglue.c üzerine bulunabilir. Kod fonksiyonla çalıştırılarak bu seçeneğe kurulur ya da IP_DROP_MEMBERSHIP aşağıdaki gibidir:
struct ip_mreqn mreq; if (optlen < sizeof(struct ip_mreq)) return -EINVAL; if (optlen >= sizeof(struct ip_mreqn)) { if(copy_from_user(&mreq,optval,sizeof(mreq))) return -EFAULT; } else { memset(&mreq, 0, sizeof(mreq)); if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq))) return -EFAULT; } if (optname == IP_ADD_MEMBERSHIP) return ip_mc_join_group(sk,&mreq); else return ip_mc_leave_group(sk,&mreq);
Kodun en baştaki satırlarında giriş parametreleri denetlenir. ip_mreq yapısı, doğru uzunluğa sahiptir ve büyük olasılıkla bunu kullanıcıdan çekirdek alanına kopyalar. Öncelikle parameternin değerini alırız, ip_mc_join_group() fonksiyonu multicast gruba bağlanmak için çağrılır ya da multicast gruptan çıkmak istiyorsak ip_mc_leave_group() fonksiyonu çağrılır.
Bu fonksiyonlar için kod /usr/src/linux/net/ipv4/igmp.c dosyasında bulunur. Gruba bağlanmayı aşağıdaki kısım sağlar :
int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) { int err; u32 addr = imr->imr_multiaddr.s_addr; struct ip_mc_socklist, *iml, *i; struct in_device *in_dev; int count = 0;
Denetlemenin en başında, MULTICAST macro'ları kullanılıyor, bu macro'lar multicast adresler için ayrılmış aralıkta değişen adreslerdir. Bu, denetleme için yeterlidir. IP adres üzerindeki en önemli byte 224'e alınır.
if (!MULTICAST(addr)) return -EINVAL; rtnl_shlock();
Denetlemeden sonra, ağ arayüzü multicast grubu aramak üzere kurulur. Eğer ağadaki bir index tarafından bu olanaklı değilse, IPv6 altında olmalıdır, ip_mc_find_dev() fonksiyonu özel IP adresine birleşecek aygıtı bulmak üzere çağrılır. Bu konuya bu yazıda değineceğiz çünkü IPv4 altında çalışıyoruz. Eğer adres INADDR_ANY ise, çekirdek ağ arayüzünü kendisi bulmalıdır, routing tablosunu okur ve burada tanımlı en iyi arayüzü gruba seçer.
if (!imr->imr_ifindex) in_dev = ip_mc_find_dev(imr); else in_dev = inetdev_by_index(imr->imr_ifindex); if (!in_dev) { iml = NULL; err = -ENODEV; goto done; }
Daha sonra ip_mc_socklist yapısı için bellek ayırırız, ve aynı grup adres ve arayüzü karşılaştırılan soketlere birleştirilir. Eğer öncesinde soketlere bir birleştirme olduysa fonksiyondan çıkarız , çünkü grup ve arayüze çift birleştirme yapamıyoruz. Eğer ağ arayüz adresi INADDR_ANY değilse, uygunluk sayacı fonksiyon tamamlanmadan artar.
iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); err = -EADDRINUSE; for (i=sk->ip_mc_list; i; i=i->next) { if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) { /* New style additions are reference counted */ if (imr->imr_address.s_addr == 0) { i->count++; err = 0; } goto done; } count++; } err = -ENOBUFS; if (iml == NULL || count >= sysctl_igmp_max_memberships) goto done;
Bu noktaya gelindiyse, bu durum yeni soketin yeni gruba linklendiği, dolayısıyla yeni girişin oluşturulması ve soketlere uygun gruplara linklenmesi gerektiği anlamına gelir. Bellek şimdiden ayrıldı, yalnızca yapıların gerektirdiği değişik alanlar için doğru değerleri kurmamız gerekiyor.
memcpy(&iml->multi,imr, sizeof(*imr)); iml->next = sk->ip_mc_list; iml->count = 1; sk->ip_mc_list = iml; ip_mc_inc_group(in_dev,addr); iml = NULL; err = 0; done: rtnl_shunlock(); if (iml) sock_kfree_s(sk, iml, sizeof(*iml)); return err; }
p_mc_leave_group() fonksiyonu multicast gruptan çıkıldığında uyarılır ve bir önceki fonksiyondan daha kolaydır. Arayüz ve grup adresleri alınır ve aktif soketlerde gerçekleşen girişlerin arasından aranır. Bir kez bulurlar, önermelerin numarası kararlaştırılır, burada en küçük bir işlem gruba birleştirilir. Eğer yeni değer sıfırsa,sayaç kendisi siler.
int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) { struct ip_mc_socklist *iml, **imlp; for (imlp=&sk->ip_mc_list;(iml=*imlp)!=NULL; imlp=&iml->next) { if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr && iml->multi.imr_address.s_addr==imr->imr_address.s_addr && (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) { struct in_device *in_dev; if (--iml->count) return 0; *imlp = iml->next; synchronize_bh(); in_dev = inetdev_by_index(iml->multi.imr_ifindex); if (in_dev) ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr); sock_kfree_s(sk, iml, sizeof(*iml)); return 0; } } return -EADDRNOTAVAIL; }
Diğer multicast seçenekleri çok basit şekilde yukarıda listelendi çünkü iç yapının veri alanlarında birleşim sağlanan soketlerle kullandığımız bazı değerleri kuruyor. Bu ayırımlar ip_setsockopt() fonksiyonu ile sağlanıyor..
|
Görselyöre sayfalarının bakımı, LinuxFocus Editörleri tarafından yapılmaktadır
© Angel Lopez, FDL LinuxFocus.org Burayı klikleyerek hataları rapor edebilir ya da yorumlarınızı LinuxFocus'a gönderebilirsiniz |
Çeviri bilgisi:
|
2001-02-26, generated by lfparser version 2.9