Linux C-メッセージキュー


一、メッセージキューの理論とAPI関数の応用
1.メッセージキューの理論
メッセージキューは、メッセージのチェーンテーブルです.メッセージをレコードと見なし、このレコードは特定のフォーマットと特定の優先度を有する.メッセージキューに書き込み権限があるプロセスは、一定のルールに従って新しいメッセージを追加できます.メッセージ・キューに読み取り権限があるプロセスは、メッセージ・キューからメッセージを読み出すことができます.
Linuxはメッセージキュー方式でメッセージ伝達を実現する.このメッセージの送信方式は、送信者が受信者が受信したメッセージをチェックするのを待つ必要がなく、受信者がメッセージを受信していない場合も待つ必要がないということである.この通信メカニズムは比較的簡単ですが、アプリケーションを使用するには比較的複雑な方法で対処する必要があります.新しいメッセージは常にキューの最後に置かれ、受信時には常に最初から受信するのではなく、真ん中から受信することができます.
メッセージ・キューは、カーネルが継続し、プロセスに関連しており、カーネルが再開されたり、メッセージ・キューの削除が表示されたりした場合にのみ、メッセージ・キューが本当に削除されます.したがって、システムに記録されたメッセージキューのデータ構造(struct ipc_ids msg_ids)はカーネルにあり、システム内のすべてのメッセージキューは構造msg_idsでアクセスエントリを見つけます.
IPC識別子:各I P Cターゲットには一意のI P C識別子があります.ここで、IPCターゲットは、個別のメッセージキュー、信号量セット、または共有メモリセグメントを指す.システムカーネルは、この識別子を使用して、システムカーネルにI P Cターゲットを示す.
IPCキーワード:一意の識別子を取得するには、I P Cキーワードを使用する必要があります.クライアント・プロセスとサーバ・エンド・プロセスの両方がこのキーワードに同意する必要があります.これは、クライアント/サーバフレームワークを構築する最初のステップです.System V IPCメカニズムでは,両端接続を確立するルーティング方法は,I P Cキーワードに直接関係する.アプリケーションでキーワード値を設定することで、使用するキーワードは毎回同じになります.一般に、f t o k()関数を使用して、クライアント側とサーバ側にキーワード値を生成することができる.
 
2.API関数の応用
①ftok関数
関数の役割:ファイル名をキー値に変換する
関数プロトタイプ:key_t ftok(char *pathname, char proj)
関数の説明:パスpathnameに対応するキー値を返します.この関数は、メッセージキューを直接操作しないが、ipcおよびmsgget()を呼び出してメッセージキュー記述語を取得する前に、関数を呼び出すことが多い.
戻り値:ファイルに対応するキー値を返します.
 
②msgget関数
関数の役割:メッセージ・キューの作成
関数プロトタイプ:int msgget(key_t key,int msgflg);
パラメータ:key:メッセージキューに関連付けられたキー.
msgflg:メッセージキューの確立フラグとアクセス権限.
             IPC_CREATカーネルにこのキューがない場合は、そのキューを作成します.
             IPC_EXCL当とIPC_CREATを併用した場合、キューが既に存在する場合は失敗します.
IPCを単独で使用する場合CREATでは、msgget()は、新しく作成されたメッセージキューの識別子を返すか、同じキーワード値を持つキューの識別子を返すかのいずれかです.IPC_の場合EXCLとIPC_CREATが一緒に使用されると、msgget()は新しいメッセージキューを作成するか、キューがすでに存在する場合は失敗値-1を返します.IPC_EXCL単独使用は役に立たない.
≪戻り値|Return Value|emdw≫:正常に実行された場合、メッセージ・キュー識別値が返されます.エラーは-1を返し、errnoは以下のいずれかの値に設定され、0を返すこともあります.この場合も正常に使用できます.
EACCES:指定されたメッセージキューは既に存在しますが、呼び出しプロセスにはアクセス権限がなく、CAP_がありません.IPC_OWNER機能
EEXIST:keyで指定されたメッセージキューはすでに存在し、msgflgではIPC_が同時に指定されています.CREATとIPC_EXCLフラグ
ENOENT:keyで指定されたメッセージキューは存在しません.また、msgflgではIPCを指定しません.CREATフラグ
ENOMEM:メッセージキューを作成する必要がありますが、メモリが不足しています.
EnOSPC:メッセージキューを確立する必要がありますが、システムの最大メッセージキュー容量に達しています.
 
③msgrcv関数
関数の役割:メッセージ・キューの読み出しに使用
関数プロトタイプ:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
パラメータ:msqid:メッセージキューの識別コード.
msgp:メッセージバッファへのポインタ.この位置は、送信および受信されたメッセージを一時的に格納するために使用され、ユーザーが定義できる汎用構造であり、形態は以下の通りである.
  struct msgbuf {
  long mtype;/* メッセージ・タイプ、必須>0*/
  char mtext[1];/* メッセージテキスト*/
  };
msgsz:メッセージのサイズ.
msgtyp:メッセージタイプ
Msgtyp=0は、キューの最初のメッセージを返します.
Msgtyp>0の場合、そのタイプがmtypeの最初のメッセージが返されます.
Msgtyp<0は、mtypeパラメータの絶対値以下のタイプの最小メッセージを返します.
msgflg:このパラメータは依然として関数の挙動を制御する標識であり、値は:0であり、無視を表すことができる.IPC_NOWAITは、メッセージキューが空の場合、ENOMSGを返し、呼び出し関数のプロセスに制御権を返します.このパラメータを指定しないと、関数がキューから条件を満たすメッセージを得るまでプロセスはブロックされます.クライアントがメッセージを待っている間にキューが削除されると、EIDRMが返されます.プロセスがブロック待ち中にシステムの割り込み信号を受信すると、EINTRが返されます.MSG_NOERRORは,関数が取得したメッセージ長がmsgszより大きい場合,msgsz長の情報のみを返し,残りの部分は破棄される.このパラメータが指定されていない場合、E 2 BIGは返され、メッセージはキューに残って取り出されません.メッセージがキューから取り出されると、対応するメッセージがキューから削除されます.
戻り値:正常に実行されると、msgrcv()はmtext配列にコピーされた実際のバイト数を返します.失敗は-1を返します
 
③msgsnd関数
関数の役割:メッセージ・キューへのデータの書き込み
関数プロトタイプ:int msgd(int msqid,const void*msgp,size_t msgsz,int msgflg);
パラメータ:msqid:メッセージキューの識別コード.
msgp:メッセージバッファへのポインタ.この位置は、送信および受信されたメッセージを一時的に格納するために使用され、ユーザーが定義できる汎用構造であり、形態は以下の通りである.
  struct msgbuf {
  long mtype;/* メッセージ・タイプ、必須>0*/
  char mtext[1];/* メッセージテキスト*/
  };
msgsz:メッセージのサイズ.
msgtyp:メッセージタイプ
Msgtyp=0は、キューの最初のメッセージを返します.
Msgtyp>0の場合、そのタイプがmtypeの最初のメッセージが返されます.
Msgtyp<0は、mtypeパラメータの絶対値以下のタイプの最小メッセージを返します.
msgflg:このパラメータは依然として関数の挙動を制御する標識であり、値は:0であり、無視を表すことができる.IPC_NOWAITは、メッセージキューが空の場合、ENOMSGを返し、呼び出し関数のプロセスに制御権を返します.このパラメータを指定しないと、関数がキューから条件を満たすメッセージを得るまでプロセスはブロックされます.クライアントがメッセージを待っている間にキューが削除されると、EIDRMが返されます.プロセスがブロック待ち中にシステムの割り込み信号を受信すると、EINTRが返されます.MSG_NOERRORは,関数が取得したメッセージ長がmsgszより大きい場合,msgsz長の情報のみを返し,残りの部分は破棄される.このパラメータが指定されていない場合、E 2 BIGは返され、メッセージはキューに残って取り出されません.メッセージがキューから取り出されると、対応するメッセージがキューから削除されます.
戻り値:正常に実行された場合、正常に実行された場合、msgsnd()は0を返します.失敗は-1を返します
 
④msgctl関数
関数の役割:メッセージ・キューの制御
関数プロトタイプ:int msgctl(int msqid,int cmd,struct msqid_ds*buf)
戻り値:0、成功した場合-1,失敗した場合:errno=EACCES(読み取り権限がなく、cmdはIPC_STAT)
 
2.メッセージ・キュー内のデータの操作方法
2つの端末を開くことで、2つの端末の通信を実現する
①受信データ
#include 
#include 
#include 
#include 
#include 
 
#include 
#include 
#include 
 
struct my_msg_st
{
    long int my_msg_type;
char some_text[BUFSIZ];
};
 
int main(void)
{
    int running=1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive=0;
 
/*      */
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid==-1)
{
    fprintf(stderr,"msgget failed with error: %d
",errno); exit(EXIT_FAILURE); } /* */ while(running) { /* */ if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0)==-1) { fprintf(stderr,"msgrcv failed with error: %d
",errno); exit(EXIT_FAILURE); } printf("You wrote: %s",some_data.some_text); /* “end” */ if(strncmp(some_data.some_text,"end",3)==0) { running=0; } } /* */ if(msgctl(msgid,IPC_RMID,0)==-1) { fprintf(stderr,"msgctl(IPC_RMID) failed
"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }

②送信データ
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MAX_TEXT 512
 
struct my_msg_st
{
    long int my_msg_type;
char some_text[MAX_TEXT];
};
 
int main(void)
{
    int running=1;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];
 
/*      */
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid==-1)
{
    fprintf(stderr,"msgget failed with error:%d
",errno); exit(EXIT_FAILURE); } /* */ while(running) { printf("Enter some text:"); fgets(buffer,BUFSIZ,stdin); some_data.my_msg_type=1; strcpy(some_data.some_text,buffer); /* */ if(msgsnd(msgid,(void *)&some_data,MAX_TEXT,0)==-1) { fprintf(stderr,"msgsed failed
"); exit(EXIT_FAILURE); } /* “end” */ if(strncmp(buffer,"end",3)==0) { running=0; } } exit(EXIT_SUCCESS); }