Linux学習ノート-プロセス間の通信-パイプ

20568 ワード

1.パイプは何ですか.なぜパイプがあるの?
オペレーティングシステムは、あるプログラムの出力を別のプログラム処理に渡し、入力出力を使用してファイルにリダイレクトできます.
    zach@zach-i16:/$ sudo ls -l / > test.txt
    zach@zach-i16:/$ wc -l test.txt
    26 test.txt
    // Linux    wc(Word Count)                 、  、  ,          
    //-c      。
    //-l     。
    //-m      。        -c       。
    //-w     。          、             。
    //-L         。
    //-help       
    //--version        

面倒に見えるので、パイプの概念が生まれます.いずれのshellでも「|」を使用して2つのコマンドを接続できます.shellは前後の2つのプロセスの入出力を1つのパイプで接続します.
    zach@zach-i16:/$ sudo ls -l | wc -l
    26

パイプは本質的に1つのファイルで、前のプロセスは書く方式でファイルを開けて、後ろのプロセスは読む方式で開けて、前は書き終わってから読んで、通信を実現しました.実装形態はファイルであるが,パイプ自体はディスクや他の外部記憶領域を占有せず,Linux実装ではメモリ領域を占有する.Linux上のパイプは、ファイルのメモリバッファとして動作します.
2.配管の分類と使用
(1)匿名配管:
最も一般的な形態はshell操作で最もよく使われる「|」です.親プロセスでのみ使用できるのが特徴で、親プロセスはサブプロセスを生成する前にパイプファイルを開く必要があり、forkはサブプロセスを生成します.このプロセスは、親プロセスのプロセスアドレス空間をコピーすることによって、同じパイプファイルの記述子を取得し、同じパイプ通信を使用する目的を達成します.親子プロセスを除いて、このパイプファイルの記述子は誰も知らないので、このパイプの情報は他のプロセスに伝達できません.伝送データの安全性を保証するとともに、パイプの汎用性を低下させる.
(2)名前付きパイプ:
mkfifoコマンドを使用して、ファイルを作成するのと同じ名前のパイプを作成できます.
    zach@zach-i16:~$ mkfifo pipe
    zach@zach-i16:~$ ls -l pipe
    prw-r--r-- 1 zach zach 0 3   29 11:35 pipe

作成されたファイルタイプはpタイプで、パイプファイルであることを示します.このパイプファイルがあれば、システムには1つのパイプのグローバル名があり、関連のない2つのプロセスはこのパイプファイルを通じて通信することができます.
For example:プロセスにこのパイプファイルを書かせる
    zach@zach-i16:~$ echo hello > pipe

パイプの反対側には誰も読んでいないので、この書き込み操作はブロックされます.これは、パイプファイルに対するカーネル定義のデフォルトの動作です.このパイプラインを読むプロセスがある場合、この書き込み操作のブロックが解除されます.
    zach@zach-i16:~$ cat pipe
    hello

catがこのファイルを終了すると、反対側のechoコマンドも返されます.
Linuxシステムは、名前付きパイプと匿名パイプにかかわらず、下位層では同じファイルシステムの動作を使用しています.このファイルシステムはpipefsと呼ばれ、/proc/filesystemsファイルでシステムがこのファイルシステムをサポートしているかどうかを見つけます.
    zach@zach-i16:/$ cat /proc/filesystems | grep pipefs
    nodev   pipefs

3.システムプログラミングでパイプを使う
(1)匿名配管(PIPE):
匿名パイプシステム呼び出しpipe()を作成します.匿名パイプを作成する関数mkfifo();//ヘッダファイルはunistdです.hプロセスでパイプを使用する:
    #include 
    #include 
    #include 
    #include 

    #define str "hello world"

    int main()
    {
        int pipefile[2];//pipefile[0]      ,        ;pipefile[1]      ,         
    char buf[BUFSIZ];//BUFSIZ        ,8192

    if(pipe(pipefile)==-1)//int pipe(int filedes[2]);       ,    -1      errno 
    {
        perror("pipe()");//perror ( )                      
        exit(1);//    
    }

    if(write(pipefile[1],str,strlen(str))<0)//write   str  strlen(str)           pipefile[1].          .     -1.    errno       
    {
        perror("write()");
        exit(1);
    }
    if(read(pipefile[0],buf,BUFSIZ)<0)// read      pipefile[0]     .   ,read          ,       0,            .  0       
    {
        perror("write()");
        exit(1);
    }
    printf("%s
"
,buf);// exit(0);// }

実行結果:
    zach@zach-i16:~/  /note/Linux/    /1.  $ gcc pipe.c -o pipe
    zach@zach-i16:~/  /note/Linux/    /1.  $ ./pipe
    hello world

プログラムはパイプを作成し、パイプに文字列を書いた後、パイプから取得し、印刷します.デュアルプロセス通信では、パイプ(半二重):
    #include 
    #include 
    #include 
    #include 
    #include //    pid_t   
    #include //  wait()    

    #define str "hello,world"

    int main()
    {
        int pipefile[2];
        pid_t pid;//     int  
        char buf[BUFSIZ];
        if(pipe(pipefile)==-1)
        {
            perror("pipe()");
            exit(1);
        }
        pid=fork();//     ,fork           ID;     ,fork  0;      ,fork      
        if(pid==-1)//    
        {
            perror("fork()");
            exit(1);
        }
        if(pid==0)//     
        {
            printf("Child pid is : %d
"
, getpid());//getpid () if(read(pipefile[0],buf,BUFSIZ)<0) { perror("write()"); exit(1); } printf("%s
"
,buf); bzero(buf,BUFSIZ);//bzero() ( ) n , :void bzero(void *s, int n); snprintf(buf,BUFSIZ,"Message from child: My pid is : %d",getpid());//buf ;BUFSIZ , ; buf , -1, errno if(write(pipefile[1],buf,strlen(buf))<0) { perror("write()"); exit(1); } } else// { printf("Parent pid is : %d
"
,getpid()); snprintf(buf,BUFSIZ,"Message from parent :My pid is : %d",getpid()); if(write(pipefile[1],buf,strlen(buf))<0) { perror("write()"); exit(1); } sleep(1);// 1 bzero(buf,BUFSIZ); if(read(pipefile[0],buf,BUFSIZ)<0) { perror("write()"); exit(1); } printf("%s
"
,buf); wait(NULL);// ,NULL 。 } exit(0); }

実行:
    zachh@zach-i16:~/  /note/Linux/    /1.  $ gcc pipen.c -o pipen
    zach@zach-i16:~/  /note/Linux/    /1.  $ ./pipen
    Parent pid is : 5099
    Child pid is : 5100
    Message from parent :My pid is : 5099
    Message from child: My pid is : 5100

同じパイプを使用すると、親子プロセスは時間を分けて相手にメッセージを送信できます.半二重の場合、パイプの両端に複数のプロセスが読み書き処理される可能性があり、複雑です.2つのプロセス通信(単一モード、1つのプロセスは読み取り専用パイプ、1つのプロセスは書き込みパイプのみ)を推奨します.
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 

    #define str "hello world"

    int main()
    {
        int pipefile[2];
        pid_t pid;
        char buf[BUFSIZ];
        if(pipe(pipefile)==-1)
        {
            perror("pipe()");
            exit(1);
        }
        pid=fork();
        if(pid==-1)
        {
            perror("fork()");
            exit(1);
        }
        if(pid==0)
        {
            close(pipefile[1]);
            printf("Child pid is : %d
"
,getpid()); if(read(pipefile[0],buf,BUFSIZ)<0) { perror("read()"); exit(1); } printf("%s
"
,buf); } else { close(pipefile[0]); printf("Parent pid is : %d
"
,getpid()); snprintf(buf,BUFSIZ,"Message from parent: My pid is: %d",getpid()); if(write(pipefile[1],buf,strlen(buf))<0) { perror("write()"); exit(1); } wait(NULL); } exit(0); }

次のように動作します.
    zach@zach-i16:~/  /note/Linux/    /1.  $ gcc pipenn.c -o pipenn
    zach@zach-i16:~/  /note/Linux/    /1.  $ ./pipenn
    Parent pid is : 5309
    Child pid is : 5310
    Message from parent: My pid is: 5309

(2)名前付きパイプ(FIFO):
mkfifo関数とnknodシステム呼び出しを使用して、名前付きパイプを作成します.
    #include 
    #include 
    #include 
    #include // /usr/include/linux/stat.h    S_IFIFO=0010000

    int main(int argc,char *argv[])
    {
        if(argc!=3)
        {
            fprintf(stderr,"Argument error
"
);//stderr exit(1); } if(mkfifo(argv[1],0600)<0)// : ,0; ,-1; argv[1] FIFO , mode FIFO ,0600==-rw------- // : //owner=rwx=4+2+1=7 //group=rw-=4+2+0=6 //others=---=0+0+0=0 { perror("mkfifo()"); exit(1); } if(mknod(argv[2],0600|S_IFIFO,0)<0)// , , 。 S_IFCHR S_IFBLK , 0 { perror("mknod()"); exit(1); } exit(0); }

運転状況:
    zach@zach-i16:~/  /note/Linux/    /1.  $ ls
    note  pipe  pipe.c  pipen  pipen.c  pipenn  pipenn.c  pipennn  pipennn.c
    zach@zach-i16:~/  /note/Linux/    /1.  $ ./pipennn pipefile1 pipefile2
    zach@zach-i16:~/  /note/Linux/    /1.  $ ls
    note  pipe.c     pipefile2  pipen.c  pipenn.c  pipennn.c
    pipe  pipefile1  pipen      pipenn   pipennn

作成後、read()、write()、open()などの操作を使用できます.操作は匿名パイプと似ています.
4.まとめ
今回のLinuxプロセス間通信の学習は、学校のオペレーティングシステムの先生が微信で共有したブログに基づいている.
貧しいゾロのLinuxの本-Linuxのプロセス間の通信-パイプの微博ID:orrozの微信の公衆番号:Linuxシステムの技術
このブログはすべて自分がその文章を勉强することに対する笔记で、文章の中のコードの中の関数の具体的なパラメータと意味はすべて1つ1つ资料を调べてしかも明らかにして、基本的にいくつかの初心者が困惑するかもしれない地方をコードのブロックの中で注釈して、しかも自分が役に立つと思っているものを书いて、ただ参考に供します