Mesaj Kuyrukları
Paylaşılan hafızaya zaten sahipken neden mesaj kuyruklarına ihtiyacımız var? Bunun birçok nedeni olabilir, basitleştirmek için bunu birden çok noktaya ayırmaya çalışalım -
Anlaşıldığı gibi, mesaj bir işlem tarafından alındığında artık başka herhangi bir işlem için mevcut olmayacaktır. Paylaşılan bellekteyken, veriler birden çok işlemin erişmesi için kullanılabilir.
Küçük mesaj formatlarıyla iletişim kurmak istiyorsak.
Birden fazla işlem aynı anda iletişim kurarken, paylaşılan hafıza verilerinin senkronizasyon ile korunması gerekir.
Paylaşılan hafızayı kullanarak yazma ve okuma sıklığı yüksektir, bu durumda işlevselliği uygulamak çok karmaşık olacaktır. Bu tür durumlarda kullanıma değmez.
Ya tüm işlemlerin paylaşılan belleğe erişmesi gerekmiyorsa, ancak çok az işlem yalnızca buna ihtiyaç duyuyorsa, ileti kuyruklarıyla uygulanması daha iyi olur.
Farklı veri paketleri ile iletişim kurmak istiyorsak, diyelim ki süreç A, B sürecine mesaj tipi 1, C işlemine mesaj tipi 10 ve D işlemine mesaj tipi 20 gönderiyor. Bu durumda, mesaj kuyrukları ile uygulamak daha basittir. Verilen mesaj tipini 1, 10, 20 olarak basitleştirmek için, aşağıda tartışıldığı gibi 0 veya + ve veya –ve olabilir.
Tabii ki, mesaj kuyruğu sırası FIFO'dur (İlk Giren İlk Çıkar). Kuyruğa eklenen ilk mesaj, alınacak ilk mesajdır.
Paylaşılan Hafıza veya Mesaj Kuyruklarının kullanılması, uygulamanın ihtiyacına ve ne kadar etkili kullanılabileceğine bağlıdır.
Mesaj kuyruklarını kullanarak iletişim aşağıdaki şekillerde gerçekleşebilir -
Bir işlemle paylaşılan belleğe yazmak ve başka bir işlemle paylaşılan bellekten okumak. Bildiğimiz gibi okuma birden fazla işlemle de yapılabilir.
Paylaşılan belleğe farklı veri paketlerine sahip bir işlemle yazmak ve ondan birden çok işlemle, yani mesaj türüne göre okumak.
Mesaj kuyruklarında belirli bilgileri gördükten sonra, artık mesaj kuyruklarını destekleyen sistem çağrısını (System V) kontrol etme zamanı geldi.
Mesaj kuyruklarını kullanarak iletişim gerçekleştirmek için aşağıdaki adımlar verilmiştir -
Step 1 - Bir mesaj kuyruğu oluşturun veya mevcut bir mesaj kuyruğuna bağlanın (msgget ())
Step 2 - Mesaj kuyruğuna yaz (msgsnd ())
Step 3 - Mesaj kuyruğundan okuyun (msgrcv ())
Step 4 - Mesaj kuyruğunda kontrol işlemlerini gerçekleştirin (msgctl ())
Şimdi, yukarıdaki çağrılarda söz dizimini ve belirli bilgileri kontrol edelim.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg)
Bu sistem çağrısı, bir System V mesaj kuyruğu oluşturur veya tahsis eder. Aşağıdaki argümanların aktarılması gerekiyor -
İlk argüman olan key, mesaj kuyruğunu tanır. Anahtar, keyfi bir değer veya ftok () kitaplık işlevinden türetilebilen bir değer olabilir.
İkinci argüman olan shmflg, IPC_CREAT (yoksa mesaj kuyruğu oluşturma) veya IPC_EXCL (mesaj kuyruğu oluşturmak için IPC_CREAT ile kullanılır ve mesaj kuyruğu zaten mevcutsa çağrı başarısız olur) gibi gerekli mesaj kuyruğu bayraklarını / larını belirtir. İzinleri de geçmeniz gerekiyor.
Note - İzinlerle ilgili ayrıntılar için önceki bölümlere bakın.
Bu çağrı, başarılı olduğunda geçerli bir mesaj kuyruğu tanımlayıcısı (mesaj kuyruğunun sonraki çağrıları için kullanılır) ve başarısızlık durumunda -1 döndürür. Başarısızlığın nedenini öğrenmek için, errno değişkeni veya perror () işlevi ile kontrol edin.
Bu çağrı ile ilgili çeşitli hatalar şunlardır: EACCESS (izin reddedildi), EEXIST (kuyruk zaten oluşturulamıyor), ENOENT (kuyruk mevcut değil), ENOMEM (kuyruğu oluşturmak için yeterli bellek yok) vb.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
Bu sistem çağrısı, mesaj kuyruğuna (System V) bir mesaj gönderir / ekler. Aşağıdaki argümanların aktarılması gerekiyor -
İlk argüman, msgid, mesaj kuyruğunu, yani mesaj kuyruğu tanımlayıcısını tanır. Tanımlayıcı değeri, msgget () başarısı üzerine alınır.
İkinci argüman, msgp, aşağıdaki formun yapısında tanımlanan, arayana gönderilen mesajın işaretçisidir -
struct msgbuf {
long mtype;
char mtext[1];
};
Mtype değişkeni, msgrcv () çağrısında ayrıntılı olarak açıklanan farklı mesaj türleri ile iletişim kurmak için kullanılır. Mtext değişkeni, boyutu msgsz (pozitif değer) ile belirtilen bir dizi veya başka bir yapıdır. Mtext alanından bahsedilmezse, izin verilen sıfır boyutlu mesaj olarak kabul edilir.
Üçüncü argüman, msgsz, mesajın boyutudur (mesaj boş bir karakterle bitmelidir)
Dördüncü bağımsız değişken olan msgflg, IPC_NOWAIT gibi belirli bayrakları gösterir (kuyrukta herhangi bir ileti bulunmadığında hemen döner veya MSG_NOERROR (msgsz bayttan fazlaysa ileti metnini keser)
Bu çağrı, başarı durumunda 0 ve başarısızlık durumunda -1 döndürür. Başarısızlığın nedenini öğrenmek için, errno değişkeni veya perror () işlevi ile kontrol edin.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msgid, const void *msgp, size_t msgsz, long msgtype, int msgflg)
Bu sistem çağrısı mesajı mesaj kuyruğundan (System V) alır. Aşağıdaki argümanların aktarılması gerekiyor -
İlk argüman, msgid, mesaj kuyruğunu, yani mesaj kuyruğu tanımlayıcısını tanır. Tanımlayıcı değeri, msgget () başarısı üzerine alınır.
İkinci argüman olan msgp, arayan kişiden alınan mesajın göstericisidir. Aşağıdaki formun yapısında tanımlanmıştır -
struct msgbuf {
long mtype;
char mtext[1];
};
Mtype değişkeni, farklı mesaj türleri ile iletişim kurmak için kullanılır. Mtext değişkeni, boyutu msgsz (pozitif değer) ile belirtilen bir dizi veya başka bir yapıdır. Mtext alanından bahsedilmezse, izin verilen sıfır boyutlu mesaj olarak kabul edilir.
Üçüncü argüman, msgsz, alınan mesajın boyutudur (mesaj boş bir karakterle bitmelidir)
İlk bağımsız değişken, msgtype, mesajın türünü gösterir -
If msgtype is 0 - Kuyruktaki ilk alınan mesajı okur
If msgtype is +ve - msgtype türündeki kuyruktaki ilk iletiyi okur (msgtype 10 ise, diğer türler başlangıçta kuyrukta olsa bile yalnızca 10 türündeki ilk iletiyi okur)
If msgtype is –ve - Mesaj türünün mutlak değerinden küçük veya ona eşit en düşük türdeki ilk mesajı okur (örneğin, msgtype -5 ise, o zaman 5'ten küçük türdeki ilk mesajı okur, yani mesaj türü 1'den 5'e kadar)
Beşinci argüman, msgflg, IPC_NOWAIT gibi belirli bayrakları gösterir (kuyrukta herhangi bir mesaj bulunmadığında hemen döner veya MSG_NOERROR (msgsz bayttan fazlaysa mesaj metnini keser)
Bu çağrı, başarı durumunda mtext dizisinde gerçekte alınan bayt sayısını ve başarısızlık durumunda -1'i döndürür. Başarısızlığın nedenini öğrenmek için, errno değişkeni veya perror () işlevi ile kontrol edin.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msgid, int cmd, struct msqid_ds *buf)
Bu sistem çağrısı, mesaj kuyruğunun (System V) kontrol işlemlerini gerçekleştirir. Aşağıdaki argümanların aktarılması gerekiyor -
İlk argüman, msgid, mesaj kuyruğunu, yani mesaj kuyruğu tanımlayıcısını tanır. Tanımlayıcı değeri, msgget () başarısı üzerine alınır.
İkinci bağımsız değişken olan cmd, mesaj kuyruğunda gerekli kontrol işlemini gerçekleştirme komutudur. Cmd için geçerli değerler -
IPC_STAT- msqid_ds yapısının her bir üyesinin mevcut değerlerinin bilgilerini tampon ile gösterilen iletilen yapıya kopyalar. Bu komut, mesaj kuyruğunda okuma izni gerektirir.
IPC_SET - Yapı buf tarafından gösterilen kullanıcı kimliğini, grup kimliğini, izinleri vb. Ayarlar.
IPC_RMID - Mesaj sırasını hemen kaldırır.
IPC_INFO - Buf ile gösterilen yapıdaki mesaj kuyruğu sınırları ve parametreleri hakkında bilgi verir, struct msginfo türü
MSG_INFO - Mesaj kuyruğu tarafından tüketilen sistem kaynakları hakkında bilgi içeren bir msginfo yapısı döndürür.
Üçüncü argüman olan buf, struct msqid_ds adlı ileti kuyruğu yapısına bir göstericidir. Bu yapının değerleri, cmd'ye göre set veya get için kullanılır.
Bu çağrı, geçirilen komuta bağlı olarak değeri döndürecektir. IPC_INFO ve MSG_INFO veya MSG_STAT'ın başarısı, mesaj kuyruğunun dizinini veya tanımlayıcısını veya diğer işlemler için 0'ı ve başarısızlık durumunda -1'i döndürür. Başarısızlığın nedenini öğrenmek için, errno değişkeni veya perror () işlevi ile kontrol edin.
Mesaj kuyruklarıyla ilgili temel bilgileri ve sistem çağrılarını gördükten sonra, şimdi bir programla kontrol etmenin zamanı geldi.
Programa bakmadan önce açıklamayı görelim -
Step 1 - Biri mesaj kuyruğuna göndermek için (msgq_send.c) ve diğeri mesaj kuyruğundan (msgq_recv.c) almak için olmak üzere iki işlem oluşturun
Step 2- ftok () işlevini kullanarak anahtarı oluşturma. Bunun için, benzersiz bir anahtar elde etmek için başlangıçta msgq.txt dosyası oluşturulur.
Step 3 - Gönderme işlemi aşağıdakileri gerçekleştirir.
Kullanıcıdan dize girdisini okur
Varsa yeni satırı kaldırır
Mesaj kuyruğuna gönderir
İşlemi girişin sonuna kadar tekrarlar (CTRL + D)
Girişin sonu alındığında, işlemin sonunu belirtmek için "son" mesajını gönderir
Step 4 - Alım sürecinde aşağıdakileri gerçekleştirir.
- Kuyruktaki mesajı okur
- Çıkışı görüntüler
- Alınan mesaj "bitti" ise, işlemi bitirir ve çıkar
Basitleştirmek için, bu örnek için mesaj türünü kullanmıyoruz. Ayrıca, bir işlem kuyruğa yazıyor ve başka bir işlem kuyruktan okuyor. Bu, gerektiğinde genişletilebilir, yani ideal olarak bir işlem kuyruğa yazabilir ve birden fazla işlem kuyruktan okunur.
Şimdi süreci kontrol edelim (sıraya mesaj gönderme) - Dosya: msgq_send.c
/* Filename: msgq_send.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PERMS 0644
struct my_msgbuf {
long mtype;
char mtext[200];
};
int main(void) {
struct my_msgbuf buf;
int msqid;
int len;
key_t key;
system("touch msgq.txt");
if ((key = ftok("msgq.txt", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, PERMS | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
printf("message queue: ready to send messages.\n");
printf("Enter lines of text, ^D to quit:\n");
buf.mtype = 1; /* we don't really care in this case */
while(fgets(buf.mtext, sizeof buf.mtext, stdin) != NULL) {
len = strlen(buf.mtext);
/* remove newline at end, if it exists */
if (buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
perror("msgsnd");
}
strcpy(buf.mtext, "end");
len = strlen(buf.mtext);
if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
perror("msgsnd");
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
printf("message queue: done sending messages.\n");
return 0;
}
Derleme ve Yürütme Adımları
message queue: ready to send messages.
Enter lines of text, ^D to quit:
this is line 1
this is line 2
message queue: done sending messages.
Mesaj alma sürecinden gelen kod aşağıdadır (kuyruktan mesaj alma) - Dosya: msgq_recv.c
/* Filename: msgq_recv.c */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PERMS 0644
struct my_msgbuf {
long mtype;
char mtext[200];
};
int main(void) {
struct my_msgbuf buf;
int msqid;
int toend;
key_t key;
if ((key = ftok("msgq.txt", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, PERMS)) == -1) { /* connect to the queue */
perror("msgget");
exit(1);
}
printf("message queue: ready to receive messages.\n");
for(;;) { /* normally receiving never ends but just to make conclusion
/* this program ends wuth string of end */
if (msgrcv(msqid, &buf, sizeof(buf.mtext), 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
printf("recvd: \"%s\"\n", buf.mtext);
toend = strcmp(buf.mtext,"end");
if (toend == 0)
break;
}
printf("message queue: done receiving messages.\n");
system("rm msgq.txt");
return 0;
}
Derleme ve Yürütme Adımları
message queue: ready to receive messages.
recvd: "this is line 1"
recvd: "this is line 2"
recvd: "end"
message queue: done receiving messages.