Antrian Pesan

Mengapa kita membutuhkan antrian pesan ketika kita sudah memiliki memori bersama? Karena berbagai alasan, mari kita coba memecahnya menjadi beberapa poin untuk penyederhanaan -

  • Seperti yang dipahami, setelah pesan diterima oleh suatu proses, pesan itu tidak lagi tersedia untuk proses lain. Sedangkan dalam memori bersama, data tersedia untuk beberapa proses untuk diakses.

  • Jika kita ingin berkomunikasi dengan format pesan kecil.

  • Data memori bersama perlu dilindungi dengan sinkronisasi ketika beberapa proses berkomunikasi pada waktu yang sama.

  • Frekuensi penulisan dan pembacaan menggunakan memori bersama yang tinggi, maka akan sangat kompleks untuk mengimplementasikan fungsionalitas tersebut. Tidak layak untuk digunakan dalam kasus semacam ini.

  • Bagaimana jika semua proses tidak perlu mengakses memori bersama tetapi sangat sedikit proses yang hanya membutuhkannya, akan lebih baik jika diterapkan dengan antrian pesan.

  • Jika kita ingin berkomunikasi dengan paket data yang berbeda, misalkan proses A mengirim tipe pesan 1 ke proses B, tipe pesan 10 ke proses C, dan tipe pesan 20 ke proses D. Dalam hal ini, lebih mudah diimplementasikan dengan antrian pesan. Untuk menyederhanakan jenis pesan yang diberikan sebagai 1, 10, 20, dapat berupa 0 atau + ve atau –ve seperti yang dibahas di bawah ini.

  • Tentu saja, urutan antrian pesannya adalah FIFO (First In First Out). Pesan pertama yang dimasukkan ke dalam antrian adalah yang pertama diambil.

Menggunakan Memori Bersama atau Antrean Pesan bergantung pada kebutuhan aplikasi dan seberapa efektif aplikasi tersebut dapat digunakan.

Komunikasi menggunakan antrian pesan dapat terjadi dengan cara berikut -

  • Menulis ke dalam memori bersama dengan satu proses dan membaca dari memori bersama dengan proses lain. Seperti yang kita sadari, membaca bisa dilakukan dengan banyak proses juga.

  • Menulis ke dalam memori bersama dengan satu proses dengan paket data yang berbeda dan membaca darinya dengan beberapa proses, yaitu, sesuai jenis pesan.

Setelah melihat informasi tertentu tentang antrian pesan, sekarang saatnya untuk memeriksa panggilan sistem (Sistem V) yang mendukung antrian pesan.

Untuk melakukan komunikasi menggunakan antrian pesan, berikut adalah langkah-langkahnya -

Step 1 - Buat antrian pesan atau hubungkan ke antrian pesan yang sudah ada (msgget ())

Step 2 - Tulis ke antrian pesan (msgsnd ())

Step 3 - Baca dari antrian pesan (msgrcv ())

Step 4 - Lakukan operasi kontrol pada antrian pesan (msgctl ())

Sekarang, mari kita periksa sintaks dan informasi tertentu pada panggilan di atas.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg)

Panggilan sistem ini membuat atau mengalokasikan antrian pesan Sistem V. Argumen berikut harus diteruskan -

  • Argumen pertama, key, mengenali antrian pesan. Kuncinya bisa berupa nilai arbitrer atau yang bisa diturunkan dari fungsi library ftok ().

  • Argumen kedua, shmflg, menentukan flag antrian pesan yang diperlukan seperti IPC_CREAT (membuat antrian pesan jika tidak ada) atau IPC_EXCL (Digunakan dengan IPC_CREAT untuk membuat antrian pesan dan panggilan gagal, jika antrian pesan sudah ada). Harus melewati izin juga.

Note - Lihat bagian sebelumnya untuk detail tentang izin.

Panggilan ini akan mengembalikan pengenal antrian pesan yang valid (digunakan untuk panggilan antrian pesan selanjutnya) saat berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().

Berbagai kesalahan sehubungan dengan panggilan ini adalah EACCESS (izin ditolak), EEXIST (antrian sudah ada tidak dapat dibuat), ENOENT (antrian tidak ada), ENOMEM (tidak cukup memori untuk membuat antrian), dll.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)

Panggilan sistem ini mengirim / menambahkan pesan ke dalam antrian pesan (Sistem V). Argumen berikut harus diteruskan -

  • Argumen pertama, msgid, mengenali antrian pesan, yaitu pengenal antrian pesan. Nilai pengenal diterima setelah keberhasilan msgget ()

  • Argumen kedua, msgp, adalah penunjuk ke pesan, yang dikirim ke pemanggil, didefinisikan dalam struktur formulir berikut -

struct msgbuf {
   long mtype;
   char mtext[1];
};

Variabel mtype digunakan untuk berkomunikasi dengan jenis pesan yang berbeda, dijelaskan secara rinci dalam panggilan msgrcv (). Variabel mtext adalah larik atau struktur lain yang ukurannya ditentukan oleh msgsz (nilai positif). Jika bidang mtext tidak disebutkan, maka itu dianggap sebagai pesan ukuran nol, yang diizinkan.

  • Argumen ketiga, msgsz, adalah ukuran pesan (pesan harus diakhiri dengan karakter null)

  • Argumen keempat, msgflg, menunjukkan flag-flag tertentu seperti IPC_NOWAIT (langsung dikembalikan ketika tidak ada pesan yang ditemukan dalam antrian atau MSG_NOERROR (memotong teks pesan, jika lebih dari byte msg)

Panggilan ini akan menghasilkan 0 jika berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().

#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)

Panggilan sistem ini mengambil pesan dari antrian pesan (Sistem V). Argumen berikut harus diteruskan -

  • Argumen pertama, msgid, mengenali antrian pesan, yaitu pengenal antrian pesan. Nilai pengenal diterima setelah keberhasilan msgget ()

  • Argumen kedua, msgp, adalah penunjuk pesan yang diterima dari pemanggil. Ini didefinisikan dalam struktur formulir berikut -

struct msgbuf {
   long mtype;
   char mtext[1];
};

Variabel mtype digunakan untuk berkomunikasi dengan tipe pesan yang berbeda. Variabel mtext adalah larik atau struktur lain yang ukurannya ditentukan oleh msgsz (nilai positif). Jika bidang mtext tidak disebutkan, maka itu dianggap sebagai pesan ukuran nol, yang diizinkan.

  • Argumen ketiga, msgsz, adalah ukuran pesan yang diterima (pesan harus diakhiri dengan karakter null)

  • Argumen pertama, jenis pesan, menunjukkan jenis pesan -

    • If msgtype is 0 - Membaca pesan pertama yang diterima dalam antrian

    • If msgtype is +ve - Membaca pesan pertama dalam antrian jenis msgtype (jika msgtype 10, maka hanya membaca pesan pertama jenis 10 meskipun jenis lain mungkin ada di antrean di awal)

    • If msgtype is –ve - Membaca pesan pertama dengan tipe terendah kurang dari atau sama dengan nilai absolut tipe pesan (katakanlah, jika msgtype adalah -5, maka pesan pertama berjenis kurang dari 5 yaitu, tipe pesan dari 1 hingga 5)

  • Argumen kelima, msgflg, menunjukkan flag-flag tertentu seperti IPC_NOWAIT (langsung dikembalikan ketika tidak ada pesan yang ditemukan dalam antrian atau MSG_NOERROR (memotong teks pesan jika lebih dari byte msg)

Panggilan ini akan mengembalikan jumlah byte yang benar-benar diterima dalam array mtext saat berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msgid, int cmd, struct msqid_ds *buf)

Panggilan sistem ini melakukan operasi kontrol antrian pesan (Sistem V). Argumen berikut harus diteruskan -

  • Argumen pertama, msgid, mengenali antrian pesan, yaitu pengenal antrian pesan. Nilai pengenal diterima setelah keberhasilan msgget ()

  • Argumen kedua, cmd, adalah perintah untuk melakukan operasi kontrol yang diperlukan pada antrian pesan. Nilai yang valid untuk cmd adalah -

IPC_STAT- Menyalin informasi dari nilai saat ini dari setiap anggota struct msqid_ds ke struktur yang dilewati yang ditunjukkan oleh buf. Perintah ini membutuhkan izin baca pada antrian pesan.

IPC_SET - Mengatur ID pengguna, ID grup dari pemilik, izin dll yang ditunjukkan oleh struktur buf.

IPC_RMID - Menghapus antrian pesan dengan segera.

IPC_INFO - Mengembalikan informasi tentang batas antrian pesan dan parameter dalam struktur yang ditunjukkan oleh buf, yang berjenis struct msginfo

MSG_INFO - Mengembalikan struktur msginfo yang berisi informasi tentang sumber daya sistem yang dikonsumsi oleh antrian pesan.

  • Argumen ketiga, buf, adalah penunjuk ke struktur antrian pesan bernama struct msqid_ds. Nilai struktur ini akan digunakan baik untuk set atau get sesuai cmd.

Panggilan ini akan mengembalikan nilai tergantung pada perintah yang diteruskan. Keberhasilan IPC_INFO dan MSG_INFO atau MSG_STAT mengembalikan indeks atau pengidentifikasi antrian pesan atau 0 untuk operasi lain dan -1 dalam kasus kegagalan. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().

Setelah melihat informasi dasar dan panggilan sistem yang berkaitan dengan antrian pesan, sekarang saatnya untuk memeriksa dengan program.

Mari kita lihat deskripsinya sebelum melihat program -

Step 1 - Buat dua proses, satu untuk mengirim ke antrian pesan (msgq_send.c) dan yang lainnya untuk mengambil dari antrian pesan (msgq_recv.c)

Step 2- Membuat kunci menggunakan fungsi ftok (). Untuk ini, awalnya file msgq.txt dibuat untuk mendapatkan kunci unik.

Step 3 - Proses pengiriman melakukan hal berikut.

  • Membaca input string dari pengguna

  • Menghapus baris baru, jika ada

  • Mengirim ke antrian pesan

  • Ulangi proses tersebut sampai akhir input (CTRL + D)

  • Setelah akhir masukan diterima, mengirimkan pesan "akhir" untuk menandai akhir dari proses

Step 4 - Dalam proses penerimaan, lakukan hal berikut.

  • Membaca pesan dari antrian
  • Menampilkan output
  • Jika pesan yang diterima adalah "end", selesaikan prosesnya dan keluar

Untuk menyederhanakan, kami tidak menggunakan jenis pesan untuk sampel ini. Selain itu, satu proses menulis ke antrian dan proses lainnya membaca dari antrian. Ini dapat diperpanjang sesuai kebutuhan yaitu, idealnya satu proses akan menulis ke dalam antrian dan beberapa proses akan dibaca dari antrian.

Sekarang, mari kita periksa prosesnya (pengiriman pesan ke antrian) - File: 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;
}

Langkah Kompilasi dan Eksekusi

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.

Berikut adalah kode dari proses penerimaan pesan (mengambil pesan dari antrian) - File: 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;
}

Langkah Kompilasi dan Eksekusi

message queue: ready to receive messages.
recvd: "this is line 1"
recvd: "this is line 2"
recvd: "end"
message queue: done receiving messages.