|
|
Bu makalenin farklı dillerde bulunduğu adresler: English Castellano Deutsch Francais Nederlands Russian Turkce |
tarafından Leonardo Giordani <leo.giordani(at)libero.it> Yazar hakkında: Milan Politechnico'da Telekoninikasyon Mühendisliğinde okuyor.Network yonetici si olarak çalışıyor ve programlama (özellikle Assembly ve C/C++) ile ilgileniyor.1999 'dan beri neredeyse sadece Linux/Unix ile çalışıyor. Türkçe'ye çeviri: Özcan Güngör <ozcangungor(at)netscape.net> İçerik: |
Eşzamanlı Programlama - İleti Kuyrukları (2)Özet: Bu makale dizisi, okuyuculara çokluişlem kavramının ve onun Linux altındaki uygulamalarının tanıtımını hedefler.Çokluişlemin temelindeki teorik kavramların tanıtımından başlayıp, basit ama etkili bir iletişim protokolü içeren bir işlemler arası iletişim uygulaması vereceğiz.Bu makalenin anlaşılabilmesi için gerekli bilgiler şunlardır:
Daha önce bu konu hakkında yayınlamış makaleleri okumak iyi olabilir:
|
Daha önce de söylediğimiz gibi, protokol, iki kişinin ya da makinanın konuşabilmesi için (farklı olsalar bile) gerekli olan kurallar kümesidir.Örneğin, İngilizce'nin kullanımı bir protokoldür. Çünkü bu dil, benim Hintli okuyucularımla( yazdıklarımla her zaman çok ilgileniyorlar) anlaşmamı sağlıyor. Daha Linux ile ilgili bir örnek vermek gerekirse, eğer kernelinizi yeniden derlerseniz (korkmayın, o kadar zor değil), Network bölümü altında, kernelinizin anlayabileceği bir çok protokol göreceksiniz.Örneğin, TCP/IP.
Bir protokol oluşturabilmemiz için önce nasıl bir uygulama geliştireceğimize karar vermeliyiz.Bu defa bir telefon anahtarı(switch) simülatörü yazacağız.Ana işlem, telefon anahtarı olacak ve oğul işlemler, kullanıcı olarak hareket edecekler: Her kullanıcıya, anahtar aracılığıyla ileti göndermesine izin vereceğiz.
Protokol üç durumun üstesinden gelecek: kullanıcının doğumu(örneğin, kullanıcı var ve bağlı), kullanıcının sıradan işleri ve kullanıcın ölümü(kullanıcı artık bağlı değil).Şimdi bu durumlar hakkında konuşalım:
Bir kullanıcı, kendi ileti kuyruğunu oluşturduğu sisteme bağlandığında (unutmayın, işlemler hakkında konuşuyoruz), anahtarın, kullanıcıya nasıl ulaşacağını bilebilmesi için, kullanıcı, kimliğini anahtara göndermelidir. Burada, gereksinim duyduğunda, bazı yapıları ve verileri başlatması için gerekli zamanı vardır.Anahtardan, anahtar aracılığı ile diğer kullanıcılara gönderilecek olan iletiyi yazacağı kuyruğun kimliğini alır.
Kullanıcı iletileri gönderebilir ve alabilir. Bir kullanıcını diğer kullanıcıya bir ileti göndermesi halinde şu iki durum oluşur: alıcı bağlıdır veya değildir. Her iki durumda da gönderene bir bilgi gönderilmesi gerektiğine karar veririz. Böylece iletisine ne olduğunu bilir. Bunu, alıcı değil, anahtar yapar.
Bir kullanıcı anahtarla bağlantısını kestiğinde, anahtarı haberdar etmelidir ve başka birşeye gerek yoktur. Bu tür bir çalışmayı tanımlayan kod aşağıdadır:
/* Birth - Doğum */ create_queue /* kuyruk_oluştur */ init /* başlat */ send_alive /* bağlı_gönder */ send_queue_id /* kuyruk_kimlik_gönder */ get_switch_queue_id /* anahtar_kuyruk_kimlik_al */ /* Work - Çalışma */ while(!leaving){ /* ayrılmıyor ise */ receive_all /* hepsini_al */ if(<send_condition>){ /* durumu_gönder ise */ send_message /* ileti_gönder */ } if(<leave condition>){ /* durumu_bırak */ leaving = 1 /* ayrılıyor=1 */ } } /* Death - Ölüm */ send_dead /* ölü_gönder */
, telefon anahtarının davranışını tanımlamalıyız: Bir kullanıcı bağlandığında, bize kendi ileti kuyruğunu kimliğini içeren bir ileti gönderir. Biz bunu, bu kullanıcıya gönderilmiş iletileti ulaştırmak için kaydetmeliyiz ve bu kullanıcının diğer ulaştırmamız üzere gönderdiği iletilerin depolanacağı ileti kuyruğunun kimliğini göndererek cevap vermeliyiz. Sonra bu kullanıcıdan gelen bütün iletileri analiz edip gönderilern kullanıcıların sisteme bağlı olup olmadığını kontrol etmeliyiz.Eğer kullanıcı bağlı ise iletiyi göndeririz, değilse iletiyi sileriz.Her iki durumda da kullanıcıyı bilgilendiririz.Bir kullanıcı öldüğünde, sadece onun ileti kuyruğunun kimliğini sileriz ve kullanucu ulaşılamaz olur.
, kod uygulaması şöyle olur:
while(1){ /* Yeni kullanıcı */ if (<birth of a user>){ /* bir kullanıcının doğumu */ get_queue_id /* kuyruk_kimlik_al */ send switch_queue_id /* gönder_anahtar_kuyruk_kimlik */ } /* Kullanıcı ölür */ if (<death of a user>){ /* kullanıcının ölümü */ remove_user /* kullanıcı_sil */ } /* İleti ulaştırması */ check_message /* ileti_kotrolü */ if (<user alive>){ /* kullanıcı_bağlı */ send_message /* ileti gönder */ ack_sender_ok /* gönderen_tamam_gönder */ } else{ ack_sender_error /* gönderen_hata_gönder */ } }
Yapacağımız ilk iş, msgbuf'ın kernel prototipini kullanarak iletiler için kendi yapımızı oluşturmalıyız
typedef struct { int service; int sender; int receiver; int data; } messg_t; typedef struct { long mtype; /* İleti tipi */ messg_t messaggio; } mymsgbuf_t;
Bu iletide daha da genişleteceğimiz genel birşeydir: Gönderen ve alan kullanıcı alanları, bir kullanıcı kimğini içerir ve veri alanı, genel veriler içerir. Servis alanı ise anahtara bir servis isteği için kullanılır. Örneğin, iki servisimizin olduğunu düşünebiliriz: biri hemen, diğeri gecikmeli ulaştırma.Bu durumda veri alanı, gecikme süresini iletir. Bu sadece bir örnektir ama servis alanın bize ne gibi olasılıklar sunduğunu anlamamızı sağlar.
Şimdi, yapımızı yonetecek olan bazı fonksiyonları uygulayabiliriz, özellikle ileti alanını alan ve dolduran fonksiyonları.Bu fonksiyonlar az çok aynıdır. Bu yüzden sadece iki tanesini vereceğim ve diğerlerini .h dosyalarında bulabilirsiniz.
void set_sender(mymsgbuf_t * buf, int sender) { buf->message.sender = sender; } int get_sender(mymsgbuf_t * buf) { return(buf->message.sender); }
Bu fonksiyonların amacı, kodu kısaltmak değil(sadece bir satırdan oluşuyor): Basitce anlamlarını hatırlamak ve protokolün insan diline daha yakı olmasımı sağlamak, böylece kullanımını kolaylaştırmak.
Şimdi, IPC anahtarlarını üretecek, ileti kuyruklarını oluşturacek ve silecek, ileti gönderecek ve alacak fonksiyonları yazmalıyız: Bir IPC anaktarı oluşturmak kolaydır:
key_t build_key(char c) { key_t key; key = ftok(".", c); return(key); }
Bir kuyruk oluşturacak fonksiyon:
int create_queue(key_t key) { int qid; if((qid = msgget(key, IPC_CREAT | 0660)) == -1){ perror("msgget"); exit(1); } return(qid); }
gördüğünüz gibi, hata ile başa çıkma, bu durumda, kolyadır.Aşağıdaki ,fonksiyon bir kuyruk siler:
int remove_queue(int qid) { if(msgctl(qid, IPC_RMID, 0) == -1) { perror("msgctl"); exit(1); } return(0); }
Son fonksiyon ileti alan ve göndern fonksiyondur: bir ileti öndermek, onu belirli bir kuyurğa yazmaktır, örneğin, bize ahantar tarafından veril olna kuyruk.
int send_message(int qid, mymsgbuf_t *qbuf) { int result, lenght; lenght = sizeof(mymsgbuf_t) - sizeof(long); if ((result = msgsnd(qid, qbuf, lenght, 0)) == -1){ perror("msgsnd"); exit(1); } return(result); } int receive_message(int qid, long type, mymsgbuf_t *qbuf) { int result, length; length = sizeof(mymsgbuf_t) - sizeof(long); if((result = msgrcv(qid, (struct msgbuf *)qbuf, length, type, IPC_NOWAIT)) == -1){ if(errno == ENOMSG){ return(0); } else{ perror("msgrcv"); exit(1); } } return(result); }
Hepsi bu. Fonksiyonları layer1.h dosyasında bulabilirsiniz: Bunları kullanarak bir program yazmaya çalışın(örneğin, geçen makaledeki örnek). Bir sonraki makalede, protokolün Katman 2'si hakkında konuşacağız ve uygulamasını yapacağız.
Bana yorumlarınızı, düzeltmeleri ve sorularını e-posta adresimden (leo.giordani(at)libero.it) ya da TalkBack sayfasından gönderebilirsiniz. Lütfen bana İngilizce, Almanca veya İtalyanca yazın.
|
Görselyöre sayfalarının bakımı, LinuxFocus Editörleri tarafından yapılmaktadır
© Leonardo Giordani, FDL LinuxFocus.org |
Çeviri bilgisi:
|
2003-05-08, generated by lfparser version 2.35