Cygwin メッセージキュー
Cygwin上でのメッセージキューの使用は色々制限がありそうで敬遠していた。しかし社内の勉強会で、非同期プログラムを扱いたくて調べてみた。本当はIPでやる方がつぶしが利くのはわかっているが、どうしてもネットワーク周りの知識が必要になる。メッセージキューはソケットに比べれば、呪文は少ないし、データ構造のキューの実践例としてはよいかも、と思ったのだ。それに、Windowsも裏ではイベントメッセージキューとメッセージポンプで動作している。それが少しでも実感できれば、と思うわけだ。
以下プリミティブなコード例
#ifndef MQ_COMMON_H__ #define MQ_COMMON_H__ #include <stdio.h> /* perror再定義 */ #define TRAP_ERR do { \ char strBuf[255]; \ sprintf(strBuf, "[%-10s][ERROR][%-10s](%05d)" \ , __FILE__, __func__, __LINE__); \ perror(strBuf); \ } while(0) #define KEYFILE_PATH "msgQueue" #define PROJ_CHAR (char)'z' #define BUFLEN (128) typedef enum { ESTRING = 1 }EMsgId; typedef union { char aText[128]; } TMsgBody; /* メッセージ構造体 */ typedef struct msgbuf { long mtype; /* message type, must be > 0 */ TMsgBody data; /* message data */ }TMsgBuf; #endif
/* mqServer.c */ #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "mqCommon.h" int main(int argc, char *argv[]) { key_t key; int idMsg; TMsgBuf msg = {0}; ssize_t rcvSize; /* キー生成 */ key = ftok(KEYFILE_PATH,PROJ_CHAR); if (key == -1) { TRAP_ERR; return 1; } /* メッセージキュー生成 */ idMsg = msgget(key, IPC_CREAT | IPC_EXCL | 0666 ) ; if (idMsg == -1) { idMsg = msgget(key, IPC_EXCL | 0666 ) ; if (idMsg == -1) { TRAP_ERR; return 1; } } /* メッセージループ */ for (;;) { /* バッファクリア */ memset(&msg, 0, sizeof(msg)); /* 受信 */ rcvSize = msgrcv(idMsg, &msg, sizeof(msg.data), 0, 0); if (rcvSize == -1) { TRAP_ERR; } else { printf("get message: %s\n", msg.data.aText); } } /* close */ msgctl(idMsg, IPC_RMID, NULL); return 0; }
/* mqClient.c */ #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/msg.h> #include "mqCommon.h" int main(int argc, char *argv[]) { key_t key; int idMsg; TMsgBuf msg = {0}; /* コマンドライン引数から、メッセージ設定 */ msg.mtype = ESTRING; strncpy(msg.data.aText, argv[1], sizeof(msg.data.aText) - 1); /* キー生成 */ key = ftok(KEYFILE_PATH,PROJ_CHAR); if (key == -1) { TRAP_ERR; return 1; } /* メッセージキュー取得 */ idMsg = msgget(key, IPC_EXCL); if (idMsg == -1) { TRAP_ERR; return 1; } /* メッセージ送信 */ if (msgsnd(idMsg, &msg, sizeof(msg.data.aText), ESTRING) == -1) { TRAP_ERR; return 1; } return 0; }
コンパイル方法
$ gcc -Wall -o server.exe mqServer.c $ gcc -Wall -o client.exe mqClient.c
実行方法
$ ./server & PIDが表示される $ ./client hello $ get message: hello