Linuxシステムコール、メッセージキューの使い方
UNIX / Linux システムコール・プログラミング
プロセス間通信(IPC)、メッセージキュー
プロセス間で一意に識別できるメッセージキューに対してメッセージを書き込み、受け取りができます。
また、メッセージキューは SYSTEM V IPC です。
メッセージキューを使うためには、まずメッセージキューを作成してユニークなキューIDを作成する必要があります。msgget()というシステムコールでキューを作成します。
メッセージを送信するためには msgsnd()、メッセージを受信するためには msgrcv()、最後にメッセージキューを削除するために msgctl() を使います。
メッセージの受信側プロセスのサンプルコードを下記に示します。
この例では、メッセージキューの key は、ftok() を使って生成しています。
ftok()は、ファイルパスからキー値を生成します。
→ ftok()を参照
ftok()に与えるパス名のファイルは、touchコマンドなどで作成してあげるとよいでしょう。
そキー値を使って msgget() でメッセージキューを取得します。引数で IPC_CREAT を指定しているので、存在しない場合は生成され、すべてのプロセスに読み書きアクセスを許可としています。
無限ループの中で msgrcv() を使ってメッセージを受信し、"Quit"の文字列を受信した場合は、ループを抜け、msgctl() を使ってメッセージキューを削除しています。
また、msgrcv()はIPC_NOWAITを指定しているのでメッセージが無い場合はすぐに制御がもどり、sleep()で3秒待ってからmsgrcv()を行っています。
次に、メッセージ送信側のサンプルコードです。
受信側と同様のパス名を ftok() に与えることで受信側と同様のキー値が得られます。
キー値は ftok() ではなく、システムで固定としても問題ありません。
こちらの msgget() では、IPC_CREAT を指定していないので、受信側が先に立ち上がっていないとエラーとなります。
このサンプルでは、メッセージタイプには PID を設定し、メッセージ本文は fgets() で入力された文字列を設定しています。
このとき、ユーザーが"Quit"と入力すれば、受信側が停止します
最後に msgsnd() でメッセージをメッセージキューに送信します。
注意!
このサンプルコードは、システムコールプログラミングの理解のためエラー処理を簡略化しています。実際の業務等で実装する場合は、エラー処理を正しく実装しましょう。
メッセージキューの状況をコマンドで確認する。
ipcsコマンドで、メッセージキューの状態を確認できます。
オプションで"-q"を指定することで、メッセージキューだけ表示することができます。
このサンプルコードは正しく終了した場合、
この場合、ipcrmコマンドで削除することができます。
ipcsで確認した、Keyで削除する場合は"-Q Key"、IDで削除する場合は"-q ID"で削除ができます。
プログラム的に対処するには、SIGINTのシグナルハンドラを実装し、その中でメッセージキューの削除を行うようにする必要があります。
Lightning Brains
プロセス間通信(IPC)、メッセージキュー
メッセージキューとは?
いわゆるメッセージボックスのような動作を行う IPC です。プロセス間で一意に識別できるメッセージキューに対してメッセージを書き込み、受け取りができます。
また、メッセージキューは SYSTEM V IPC です。
メッセージキューを使うためには、まずメッセージキューを作成してユニークなキューIDを作成する必要があります。msgget()というシステムコールでキューを作成します。
メッセージを送信するためには msgsnd()、メッセージを受信するためには msgrcv()、最後にメッセージキューを削除するために msgctl() を使います。
メッセージの受信側プロセスのサンプルコードを下記に示します。
#include <sys/types.h> #include <stdio.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #include <unistd.h> #define MSGBUFSIZ 256 int main(int argc, char** argv) { int msqid; key_t msgkey; struct msgbuf{ long mtype; char mdata[MSGBUFSIZ]; }; struct msgbuf msgdata,*p; p = &msgdata; // Make Message queue key. msgkey = ftok("msgq.key",'X'); // Get Message queue ID. msqid = msgget(msgkey,IPC_CREAT|0666); // Message receive loop wile get "Quit" massage. while(1) { // Receive a Message. if(msgrcv(msqid,p,sizeof(p->mdata),0,IPC_NOWAIT)<=0) { printf("No message\n"); sleep(3); continue; } printf("message received from %ld\n%s\n",p->mtype,p->mdata); if(strncmp((char*)p->mdata, "Quit", (size_t)3)==0) break; } // Remove Message Queue msgctl(msqid, IPC_RMID, 0); }
この例では、メッセージキューの key は、ftok() を使って生成しています。
ftok()は、ファイルパスからキー値を生成します。
→ ftok()を参照
ftok()に与えるパス名のファイルは、touchコマンドなどで作成してあげるとよいでしょう。
そキー値を使って msgget() でメッセージキューを取得します。引数で IPC_CREAT を指定しているので、存在しない場合は生成され、すべてのプロセスに読み書きアクセスを許可としています。
無限ループの中で msgrcv() を使ってメッセージを受信し、"Quit"の文字列を受信した場合は、ループを抜け、msgctl() を使ってメッセージキューを削除しています。
また、msgrcv()はIPC_NOWAITを指定しているのでメッセージが無い場合はすぐに制御がもどり、sleep()で3秒待ってからmsgrcv()を行っています。
次に、メッセージ送信側のサンプルコードです。
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <unistd.h> #define MSGBUFSIZ 256 int main(int argc, char** argv) { int msqid; key_t msgkey; struct msgbuf{ long mtype; char mdata[MSGBUFSIZ]; }; struct msgbuf msgdata,*p; // Make Message queue key. msgkey = ftok(argv[1], 'X'); // Get Message queue ID. (Only get existing message queue.) msqid = msgget(msgkey, 0666); printf("QID = %d\n", msqid); if(msqid<0 -1="" fflush="" fgets="" nter="" p-="" p="&msgdata;" printf="" return="" stdin="">mdata,MSGBUFSIZ,stdin); p->mtype = getpid(); // Message send. msgsnd(msqid,p,sizeof(p->mdata),0); } 0>
受信側と同様のパス名を ftok() に与えることで受信側と同様のキー値が得られます。
キー値は ftok() ではなく、システムで固定としても問題ありません。
こちらの msgget() では、IPC_CREAT を指定していないので、受信側が先に立ち上がっていないとエラーとなります。
このサンプルでは、メッセージタイプには PID を設定し、メッセージ本文は fgets() で入力された文字列を設定しています。
このとき、ユーザーが"Quit"と入力すれば、受信側が停止します
最後に msgsnd() でメッセージをメッセージキューに送信します。
注意!
このサンプルコードは、システムコールプログラミングの理解のためエラー処理を簡略化しています。実際の業務等で実装する場合は、エラー処理を正しく実装しましょう。
メッセージキューの状況をコマンドで確認する。
ipcsコマンドで、メッセージキューの状態を確認できます。
オプションで"-q"を指定することで、メッセージキューだけ表示することができます。
このサンプルコードは正しく終了した場合、
msgctl(msqid, IPC_RMID, 0);で、メッセージキューを削除していますが、Ctrl+cで抜けた場合はメッセージキューが残ってしまいます。
この場合、ipcrmコマンドで削除することができます。
ipcsで確認した、Keyで削除する場合は"-Q Key"、IDで削除する場合は"-q ID"で削除ができます。
プログラム的に対処するには、SIGINTのシグナルハンドラを実装し、その中でメッセージキューの削除を行うようにする必要があります。
Lightning Brains
コメント
コメントを投稿