1: 実験テーマ
Linuxのプロセス間通信
2: 実験の目的
Linux システムのプロセス通信機構 (IPC) により、任意のプロセス間で大量のデータ交換が可能になります。
Linux でサポートされているメッセージ通信メカニズムに精通している。
3: 実験内容 (実験原理/使用される理論的知識、アルゴリズム/プログラムのフローチャート、手順と方法、キーコード)
実験原理:主に4つの機能を使用
int msgget(key_t key, int msgflag);
key: メッセージ キューの名前。frok() (関数 frok の戻り値) または IPC_PRIVATE によって生成され、メッセージ キューの識別子を取得し、メッセージ キューを作成してアクセスします。
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msqid: msgget によって取得されるメッセージ キュー識別子。
cmd: 制御識別子、IPC_SET コマンド: 所有者のユーザー識別子とグループ識別子を設定、IPC_STAT および IPC_INFO コマンド: リソースのステータス情報を取得、IPC_RMID コマンド: このリソースを解放します。
buf: メッセージ キュー管理構造。メッセージ キュー カーネル構造の説明を参照してください。
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msqid: メッセージキュー識別子。
msgp: キューに送信されたメッセージ。msgp は任意のタイプの構造体にすることができますが、最初のフィールドは送信されたメッセージのタイプを示す long タイプである必要があり、msgrcv はこれに従ってメッセージを受信します。msgp で定義される参照形式は次のとおりです。
struct s_msg{ /*msgp で定義された参照形式*/
long 型; /* 0 より大きくなければなりません、メッセージ タイプ*/
char mtext[256]; /*メッセージテキスト、他のタイプも可能*/
msgp;
msgsz: メッセージ タイプによって占有される 4 バイトを除いた、送信されるメッセージのサイズ、つまり mtext の長さ。
msgflg: コアの内部バッファー領域が不足した場合の動作を指定する制御ビット
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msqid: メッセージキュー識別子。
msgp: メッセージを保存するための構造体。構造体の型は、msgsnd 関数によって送信される型と同じである必要があります。
msgsz: 受信するメッセージのサイズ (メッセージ タイプによって占有される 4 バイトを除く)。
msgtyp: 0: 最初のメッセージを受信します; >0: タイプが msgtyp と等しい最初のメッセージを受信します; <0: タイプが msgtyp の絶対値以下の最初のメッセージを受信します。
msgflg: キューにメッセージがない場合にコアが行うべきことを指定します。この時点で IPC_NOWAIT フラグが設定されている場合、すぐに戻ります。フラグに MSG_NOERROR が設定されており、受信メッセージのサイズがサイズが大きい場合、コアは受信したメッセージを切り捨てます。
msgrcv() のブロックを解除するには 3 つの条件があります。
1. メッセージキューに条件を満たすメッセージが存在します。
2. msqid で表されるメッセージ キューが削除されます。
3. msgrcv() を呼び出すプロセスがシグナルによって中断されます。
以上の4つの機能を利用して、Linuxシステム上での通信を実現します。
4: 実験結果と分析
結果分析:
プログラムはまず、プロセス間でメッセージを受け渡すためのメッセージ キューを作成します。msgget() 関数を使用してメッセージ キューを作成し、メッセージ キューのキー値を MSGKEY として指定します。
次に、プログラムは fork() 関数を呼び出して子プロセスを作成します。子プロセスの SERVER() 関数をサーバー プロセスとして呼び出し、親プロセスの CLIENT() 関数をクライアント プロセスとして呼び出します。
サーバー プロセスは、msgrcv() 関数を呼び出してメッセージを受信し、「(サーバー) を受信しました」と出力します。サーバー プロセスは、メッセージ タイプ 1 のメッセージを受信するまでメッセージを受信し続けます。
クライアント プロセスは、msgsnd() 関数を呼び出してメッセージ キューにメッセージを送信し、「(クライアント) 送信済み」を出力します。クライアント プロセスは、異なるタイプの 10 個のメッセージを 10 から 1 まで送信します。
サーバープロセスは、メッセージタイプが 1 のメッセージを受信すると、msgctl() 関数を呼び出してメッセージキューを削除し、プロセスを終了します。
メインプロセスは、wait() 関数を 2 回呼び出して、子プロセスの終了を待ちます。
分析します:
クライアント プロセスが最初に実行され、連続して 10 個のメッセージをメッセージ キューに送信します。
サーバー プロセスは、最初のメッセージを受信すると「(サーバー) を受信しました」と出力し、その後、他のメッセージの受信を待機するループに入ります。
サーバー プロセスがタイプ 1 のメッセージ (10 番目のメッセージ) を受信すると、「(サーバー) を受信しました」と出力されます。
メインプロセスは子プロセスが終了するまで待機します。
プロセスのスケジューリングの不確実性とメッセージ受け渡しの非同期性により、実際の実行結果は異なる場合があることに注意してください。上記の結果は、考えられるシナリオの 1 つを示しているにすぎません。
5. まとめと経験
1. プロセス間通信: この実験では、メッセージ キューを介したプロセス間通信を実装します。サーバー プロセスは msgrcv() 関数を通じてメッセージを受信し、クライアント プロセスは msgsnd() 関数を通じてメッセージを送信します。メッセージ キューは、プロセス間の非同期対話を可能にする信頼性の高い通信メカニズムを提供します。
2. メッセージ キュー: メッセージ キューはメッセージを格納するコンテナであり、プロセスはキューにメッセージを送信したり、キューからメッセージを受信したりできます。各メッセージには、さまざまなメッセージを識別するメッセージ タイプがあります。この実験では、サーバー プロセスは、タイプ 1 のメッセージを受信するまで、メッセージ タイプ 0 を指定してすべてのタイプのメッセージを受信します。
3. プロセス間同期: 実験では、サーバー プロセスは特定の種類のメッセージを受信するまで終了しません。このメソッドはプロセス間の同期を実現し、サーバー プロセスは指定されたメッセージを受信するまで待機します。
4. fork() 関数の使用: 実験では、fork() 関数を使用して子プロセスを作成しました。fork() 関数を複数回呼び出すことで、サーバー プロセスとクライアント プロセスを作成する目的が達成されます。子プロセスは親プロセスのメッセージキュー識別子を継承するため、メッセージを送受信できます。
5. 親プロセスと子プロセスの連携: fork()関数で作成された子プロセスはそれぞれ異なる機能を実行することで、親プロセスと子プロセスの連携を実現します。クライアント プロセスはメッセージを送信し、サーバー プロセスはメッセージを受信し、相互に連携して通信タスクを完了します。
6. 非同期メッセージング: メッセージングは非同期であるため、クライアント プロセスは複数のメッセージを迅速に送信でき、サーバー プロセスは独自のペースでメッセージを受信できます。この非同期により、システムの応答速度と同時実行パフォーマンスが向上します。