09
5月
2007

メッセージキュー

メッセージキューはパイプとより扱いが簡単でちょっと嬉しい.
メッセージキューに関する関数
サンプル

メッセージキューに関する関数

メッセージキューに関する関数として,以下がある.
int msgget(key_t key, int msgflg);
指定したkeyのメッセージキュー識別子を取得.msgflgにはパーミッションやオプションなどを指定する.これにIPC_CREATを指定すると,指定したkeyのメッセージキューがない場合は作成してくれる.
int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
メッセージの送信.
ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg);
メッセージの受信.
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
メッセージキューの制御.メッセージキューを消したりできる.
パターンとしては,以下のようになるだろうか.
msggetでメッセージキューを作成,取得する.
msgsndで送信,msgrcvで受信.
msgctlでメッセージキューを削除する.

サンプル

以上を踏まえてサンプルを示す.まず送信側.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/* ��å��������塼�������������å�����
   msgsnd,msgrcv��*msgp�ˤϤ��ι�¤�ΤؤΥݥ��󥿤򤤤�� */
struct msgbuf{
  /* ��å���������Ƭ�Ϥ��ʤ餺long int���Ǥʤ���Фʤ�ʤ� */
  long int type;
  char data[BUFSIZ];
};

int main(int argc, char *argv[])
{
  /* ��å��������塼��ID */
  int msqid;
  /* ������ */
  struct msgbuf message;

  /* �ѥ�᡼�������å� */
  if(argc != 3){
    fprintf(stderr,"Usage: %s type string\n",argv[0]);
    exit(EXIT_FAILURE);
  }else{
    /* message��type�����Ǥʤ���Фʤ�ʤ� */
    if((message.type = atol(argv[1])) <= 0){
      fprintf(stderr,"type value is invalid\n");
      exit(EXIT_FAILURE);
    }
    strncpy(message.data,argv[2],BUFSIZ);
  }

  /* ��å��������塼�κ���,���� */
  errno = 0;
  if((msqid = msgget((key_t)1111, 0666 | IPC_CREAT)) == -1){
    perror("msgget failure");
    exit(EXIT_FAILURE);
  }

  /* ������������ */
  errno = 0;
  if(msgsnd(msqid, &message, BUFSIZ, 0) == -1){
    perror("msgsnd failure");
    exit(EXIT_FAILURE);
  }

  exit(EXIT_SUCCESS);
}

そして受信側.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/* ��å��������塼�������������å�����
   msgsnd,msgrcv��*msgp�ˤϤ��ι�¤�ΤؤΥݥ��󥿤򤤤�� */
struct msgbuf{
  /* ��å���������Ƭ�Ϥ��ʤ餺long int���Ǥʤ���Фʤ�ʤ� */
  long int type;
  char data[BUFSIZ];
};

int main(int argc, char *argv[])
{
  /* ��å��������塼��ID */
  int msqid;
  /* ������ */
  struct msgbuf message;
  long int read_type;

  /* �ѥ�᡼�������å� */
  if(argc != 2){
    fprintf(stderr,"Usage: %s type\n",argv[0]);
    exit(EXIT_FAILURE);
  }else{
    /* ���������פ����� */
    read_type = atol(argv[1]);
  }

  /* ��å��������塼�κ���,���� */
  errno = 0;
  if((msqid = msgget((key_t)1111, 0666 | IPC_CREAT)) == -1){
    perror("msgget failure");
    exit(EXIT_FAILURE);
  }

  while(1){
    /* ��å������μ��� */
    errno = 0;
    if(msgrcv(msqid, &message, BUFSIZ, read_type, 0) == -1){
      perror("msgrcv failure");
      break;
    }else{
      fprintf(stdout,"received message:\t%s\n",message.data);
    }
    /* "exit"���������Ƚ�λ���� */
    if(strcmp(message.data, "exit") == 0){
      break;
    }
  }

  /* ��å��������塼�κ�� */
  errno = 0;
  if(msgctl(msqid, IPC_RMID, NULL) == -1){
    perror("msgctl failure");
    exit(EXIT_FAILURE);
  }

  exit(EXIT_SUCCESS);
}
メッセージは構造体を介して送受信する.この構造体はサンプルのmsgbufのように最初のフィールドをlong int型にしてメッセージタイプ(正の整数)を指定する.サンプルの送信側mq-sndでは引数にこのメッセージタイプとメッセージ文字列を引数に渡す.
$ ./mq-snd 2 type2
$ ./mq-snd 3 type3
$ ./mq-snd 1 type1
メッセージキューが一杯だと,メッセージキューに空きがでるまで待たされる.ノンブロッキンブモードにするには,msgsndのmsgflgにIPC_NOWAITを指定する.サンプルの受信側mq-rcvでは,受信するメッセージタイプを引数に渡す.
$ ./mq-rcv -2
received message:       type2
received message:       type1
あらかじめ先のmq-sndを実行していた場合の結果である.上の様に負の数を渡すと,そのタイプの値以下のメッセージをキューから取り出す.取り出されなかったメッセージはキューに残っている.
$ ./mq-rcv 0 
received message:       type3
この様にtypeに0を指定するとすべてのtypeがマッチする(注:mq-sndで文字列exitを送信してmq-rcvを終了すると,mq-rcv内でメッセージキューを削除するので,上の結果にはならない).

You may also like...