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