□メッセージキューの使い方(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"; } ?>