Linux学習ノート-プロセス間の通信-パイプ
20568 ワード
1.パイプは何ですか.なぜパイプがあるの?
オペレーティングシステムは、あるプログラムの出力を別のプログラム処理に渡し、入力出力を使用してファイルにリダイレクトできます.
面倒に見えるので、パイプの概念が生まれます.いずれのshellでも「|」を使用して2つのコマンドを接続できます.shellは前後の2つのプロセスの入出力を1つのパイプで接続します.
パイプは本質的に1つのファイルで、前のプロセスは書く方式でファイルを開けて、後ろのプロセスは読む方式で開けて、前は書き終わってから読んで、通信を実現しました.実装形態はファイルであるが,パイプ自体はディスクや他の外部記憶領域を占有せず,Linux実装ではメモリ領域を占有する.Linux上のパイプは、ファイルのメモリバッファとして動作します.
2.配管の分類と使用
(1)匿名配管:
最も一般的な形態はshell操作で最もよく使われる「|」です.親プロセスでのみ使用できるのが特徴で、親プロセスはサブプロセスを生成する前にパイプファイルを開く必要があり、forkはサブプロセスを生成します.このプロセスは、親プロセスのプロセスアドレス空間をコピーすることによって、同じパイプファイルの記述子を取得し、同じパイプ通信を使用する目的を達成します.親子プロセスを除いて、このパイプファイルの記述子は誰も知らないので、このパイプの情報は他のプロセスに伝達できません.伝送データの安全性を保証するとともに、パイプの汎用性を低下させる.
(2)名前付きパイプ:
mkfifoコマンドを使用して、ファイルを作成するのと同じ名前のパイプを作成できます.
作成されたファイルタイプはpタイプで、パイプファイルであることを示します.このパイプファイルがあれば、システムには1つのパイプのグローバル名があり、関連のない2つのプロセスはこのパイプファイルを通じて通信することができます.
For example:プロセスにこのパイプファイルを書かせる
パイプの反対側には誰も読んでいないので、この書き込み操作はブロックされます.これは、パイプファイルに対するカーネル定義のデフォルトの動作です.このパイプラインを読むプロセスがある場合、この書き込み操作のブロックが解除されます.
catがこのファイルを終了すると、反対側のechoコマンドも返されます.
Linuxシステムは、名前付きパイプと匿名パイプにかかわらず、下位層では同じファイルシステムの動作を使用しています.このファイルシステムはpipefsと呼ばれ、/proc/filesystemsファイルでシステムがこのファイルシステムをサポートしているかどうかを見つけます.
3.システムプログラミングでパイプを使う
(1)匿名配管(PIPE):
匿名パイプシステム呼び出しpipe()を作成します.匿名パイプを作成する関数mkfifo();//ヘッダファイルはunistdです.hプロセスでパイプを使用する:
実行結果:
プログラムはパイプを作成し、パイプに文字列を書いた後、パイプから取得し、印刷します.デュアルプロセス通信では、パイプ(半二重):
実行:
同じパイプを使用すると、親子プロセスは時間を分けて相手にメッセージを送信できます.半二重の場合、パイプの両端に複数のプロセスが読み書き処理される可能性があり、複雑です.2つのプロセス通信(単一モード、1つのプロセスは読み取り専用パイプ、1つのプロセスは書き込みパイプのみ)を推奨します.
次のように動作します.
(2)名前付きパイプ(FIFO):
mkfifo関数とnknodシステム呼び出しを使用して、名前付きパイプを作成します.
運転状況:
作成後、read()、write()、open()などの操作を使用できます.操作は匿名パイプと似ています.
4.まとめ
今回のLinuxプロセス間通信の学習は、学校のオペレーティングシステムの先生が微信で共有したブログに基づいている.
貧しいゾロのLinuxの本-Linuxのプロセス間の通信-パイプの微博ID:orrozの微信の公衆番号:Linuxシステムの技術
このブログはすべて自分がその文章を勉强することに対する笔记で、文章の中のコードの中の関数の具体的なパラメータと意味はすべて1つ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つ资料を调べてしかも明らかにして、基本的にいくつかの初心者が困惑するかもしれない地方をコードのブロックの中で注釈して、しかも自分が役に立つと思っているものを书いて、ただ参考に供します