Linux Install Memo

サーバー管理者によるLinux関連ソフトのインストールメモ

Home » □メッセージキューの使い方(CとPHPでプロセス間通信)

□メッセージキューの使い方(CとPHPでプロセス間通信)

C言語で作ったプロセス同士はもちろん、C言語で作ったプロセスとPHPで作ったスクリプト間でもメッセージキューであれこれやり取りしたい。手順としては、とりあえずC言語側でもPHPでも同じ。

 http://www.fireproject.jp/feature/c-language/ipc/message-queue.html

より、メッセージキューの実験

semmainで作ったセマフォをsemotherでロック、すると別のsemotherを起動すると先に起動したsemotherが終わるまで後からのは待つ

cat > sendque.c

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

// バッファサイズBUFSIZは8192バイトもあるのでもったいないから1024にする。
#define BUFFSIZE 1024


/* メッセージキューで送受信するメッセージ
   msgsnd,msgrcvの*msgpにはこの構造体へのポインタをいれる */
struct msgbuf{
  /* メッセージの先頭はかならずlong int型でなければならない */
  long int type;
  char data[BUFFSIZE];
};

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],BUFFSIZE);
  }

  printf("BUFFSIZEEは%0dバイトです\n",BUFFSIZE);

  /* メッセージキューの作成,取得 */
  errno = 0;
  if((msqid = msgget((key_t)1111, 0666 | IPC_CREAT)) == -1){
    perror("msgget failure");
    exit(EXIT_FAILURE);
  }

  /* メッセージを送信 */
  errno = 0;
  if(msgsnd(msqid, &message, BUFFSIZE, 0) == -1){
    perror("msgsnd failure");
    exit(EXIT_FAILURE);
  }

  exit(EXIT_SUCCESS);
}

gcc -O2 sendque.c -o sendque

cat > rcvque.c

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

// バッファサイズBUFSIZは8192バイトもあるのでもったいないから1024にする。
#define BUFFSIZE 1024

/* メッセージキューで送受信するメッセージ
   msgsnd,msgrcvの*msgpにはこの構造体へのポインタをいれる */
struct msgbuf{
  /* メッセージの先頭はかならずlong int型でなければならない */
  long int type;
  char data[BUFFSIZE];
};

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, BUFFSIZE, 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);
}

gcc -O2 rcvque.c -o rcvque

できたら、

./sendque 111 aaaaa
./sendque 333 ccccc
./sendque 222 bbbbb
./sendque 444 ddddd
./sendque 555 exit

と送ってみて、別プロセスで

./rcvque 333

とかすると該当するtype(ID)のメッセージを取ってこれる

これをPHPで受けるとすると、上記のサンプルソースではキューのキーが「1111」なので、以下のようなスクリプトで存在を確認できる。

<?php

$QKEY = 1111;

if (msg_queue_exists($QKEY))
{
    print $QKEY."はあります\n";
}
else
{
    print $QKEY."がありません!?\n";
}
?>

このキューに実際にアクセスするには msg_get_queue() で一度リソースを取得する必要がある。

<?php

$QKEY = 1111;
$QUEUE = msg_get_queue($QKEY, 0666);

if (msg_queue_exists($QKEY))
{
//    var_dump(msg_stat_queue($QUEUE));
    // キューの先頭からの
    if (msg_receive($QUEUE, 0, $MSGTYPE, 4096, $MSGDATA, FALSE, MSG_IPC_NOWAIT | MSG_NOERROR, $ERRCODE) == TRUE)
    {
        print "TYPE:".$MSGTYPE." MSG:".$MSGDATA."\n";
    }
    else
    {
        if ($ERRCODE & MSG_NOERROR)
        {
            print "キューにデータがありませんでした!?\n";
        }
        else
        {
            print "キューから取得できませんでした!?\n";
        }
    }
}
else
{
    print "キューがありません!?\n";
}
?>

Name of author

Name: admin

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です