Linuxシステムコールの勉強(その14)

Linuxシステムコール

Linuxシステムコール

前回はこちら


今回から名前付きパイプを使ったプロセス間通信についてまとめます。
前回までやっていた匿名パイプはファイルディスクリプタを介してパイプへデータを書込んだり、読み込んだりしていました。つまりパイプには名前がありませんでした。
今回からまとめる名前付きパイプはスペシャルファイルと呼ばれる特殊なファイルを介してデータをやりとりします。ファイルには当然名前があり、その名前を使用してデータを読み書きするので「名前付き」とわざわざ呼んでいるようです。


名前付きパイプを利用する方法としては以下の方法があります。


1. mknodコマンドを利用した方法

mknodというコマンドは名前付きパイプに限らず、スペシャルファイルを作成するためのコマンドです。

[itotto@itotto ]$ \ls -l
合計 8
drwxr-xr-x 2 itotto itotto 4096 112001:04 executable/
drwxr-xr-x 2 itotto itotto 4096 112001:04 source/

[itotto@itotto ]$ mknod named_pipe p

[itotto@itotto ]$ \ls -l
合計 8
drwxr-xr-x 2 itotto itotto 4096 112001:04 executable/
prw-r--r-- 1 itotto itotto    0 112101:47 named_pipe|
drwxr-xr-x 2 itotto itotto 4096 112001:04 source/

[itotto@itotto ]$

named_pipe という名前でファイルが作成されています。さらに詳しく見てみると

 prw-r--r-- 1 itotto itotto    0 112101:47 named_pipe|
↑pというのがファイルの種類がパイプである事を示しています

となっています。ちなみに上記のファイル名の末尾に|が付いているのもパイプである事を示唆しています。


2. mkinfoコマンドを利用した方法

mkfifoはその名のとおり、fifoをmakeするコマンドです。つまりパイプ作成専用コマンドです。使い方はほとんどmknodと同じですが、専用コマンドですので引数を指定する必要がありません。

[itotto@itotto ]$ \ls -l
合計 8
drwxr-xr-x 2 itotto itotto 4096 112001:04 executable/
drwxr-xr-x 2 itotto itotto 4096 112001:04 source/

[itotto@itotto ]$ mkfifo named_pipe

[itotto@itotto ]$ \ls -l
合計 8
drwxr-xr-x 2 itotto itotto 4096 112001:04 executable/
prw-r--r-- 1 itotto itotto    0 112101:47 named_pipe|
drwxr-xr-x 2 itotto itotto 4096 112001:04 source/

[itotto@itotto ]$


3. システムコールを利用した方法

mknod()システムコールかもしくはmkfifo()関数を使用する。よく見たら上のコマンドと名前が一緒なので特に説明は要らなさそう。

/*** ノードを作成する ***/
// #include <unistd.h>
// #include <sys/types.h>
// #include <sys/stat.h>
// #include <fcntl.h>
// 
// 第一引数 pathname - ファイル名
// 第二引数 mode     - 作成するノードの設定値
// 第三引数 dev      - デバイスファイル以外は指定する必要なし
//
// 返却値
//  成功時 :  0
//  失敗時 : -1
int mknod(const char *pathname, mode_t mode, dev_t dev);


パイプ作成のサンプルは以下のとおりです。

      1 #include <unistd.h>
      2 #include <sys/stat.h>
      3 #include <stdio.h>
      4
      5 #define FILENAME    "/home/itotto/pg/c/named_pipe"
      6
      7 int main()
      8 {
      9     if (access(FILENAME, F_OK) == -1)
     10     {
     11         if (mknod(FILENAME, 0666 | S_IFIFO, 0) == -1)
     12         {
     13             perror("mknod()");
     14             return 1;
     15         }
     16         else
     17         {
     18             printf("パイプ(%s)を作成しました\n", FILENAME);
     19         }
     20     }
     21     else
     22     {
     23         printf("パイプ(%s)は既に存在します\n", FILENAME);
     24     }
     25
     26     return 0;
     27 }


説明し忘れていましたが、access()はファイルのpermissionを取得するためのシステムコールです。これがファイルの有無チェックにも使用できるようです。
# ↓定義はこんな感じ

/*** ファイルのpermissionチェック ***/
// #include <unistd.h>
// 
// 第一引数 pathname - ファイル名
// 第二引数 mode     - permissionのbit pattern
//
// 返却値
//  許可されている  :  0
//  許可されていない : -1
int access(const char *pathname, int mode);


ではプログラムを早速実行してみます。

[itotto@itotto ]$ \ls -l
合計 12
drwxr-xr-x 2 itotto itotto 4096 112001:04 executable/
-rw-r--r-- 1 itotto itotto  401 112102:19 mkmypipe.c
drwxr-xr-x 2 itotto itotto 4096 112001:04 source/

[itotto@itotto ]$ gcc -o mkmypipe mkmypipe.c

[itotto@itotto ]$ ./mkmypipe
パイプ(/home/itotto/pg/c/named_pipe)を作成しました

[itotto@itotto ]$ \ls -l
合計 20
drwxr-xr-x 2 itotto itotto 4096 112001:04 executable/
-rwxr-xr-x 1 itotto itotto 5300 112102:19 mkmypipe*
-rw-r--r-- 1 itotto itotto  401 112102:19 mkmypipe.c
prw-r--r-- 1 itotto itotto    0 112102:19 named_pipe|
drwxr-xr-x 2 itotto itotto 4096 112001:04 source/

[itotto@itotto ]$ ./mkmypipe
パイプ(/home/itotto/pg/c/named_pipe)は既に存在します

[itotto@itotto ]$


ファイルの有無チェックも含めて正常に動作している事が分かります。


続いてパイプの使用方法について。入力側と読み取り側で別のコンソールが必要になるので、二つの端末を立ち上げてください。


まず、パイプと言ってますが、一見普通のファイルですので試しにデータを書き込んで見ます。


[端末1]

[itotto@itotto ]$ \ls -l
合計 8
drwxr-xr-x 2 itotto itotto 4096 112113:21 executable/
prw-r--r-- 1 itotto itotto    0 112102:19 named_pipe|
drwxr-xr-x 2 itotto itotto 4096 112113:21 source/

[itotto@itotto ]$ echo I am itotto > named_pipe

↑ここで止まる

ファイルへ標準出力経由でデータをリダイレクトしたところで何も応答がなくなってしまいました。この状態でもう一つの端末を操作します。


[端末2]

[itotto@itotto ]$ \ls -l
合計 8
drwxr-xr-x 2 itotto itotto 4096 112113:21 executable/
prw-r--r-- 1 itotto itotto    0 112113:25 named_pipe|
drwxr-xr-x 2 itotto itotto 4096 112113:21 source/

[itotto@itotto ]$ cat named_pipe
I am itotto

[itotto@itotto ]$

named_pipeの中をcatで覗いてみると、先ほど[端末1]でリダイレクトしたデータを読み取る事が出来ます。ここでもう一度[端末1]へ戻ってみると先ほど止まっていた場所から先に進んでいる事がわかります。


[端末1]

[itotto@itotto ]$ echo I am itotto > named_pipe ←さっきはここで止まってた

[itotto@itotto ]$


名前付きパイプにデータを書き込んだ場合には、誰かにそれを受け取ってもらわない限り応答が返ってこなくなるようです。便利なような不便なような微妙な名前付きパイプ...。


次回はもっと便利に使いこなす方法をまとめます。


次へ進む