linux学習の18---パイプpipe&dup&dup 2


一、パイプ(pipe)の使い方:
プロセスはfork関数を使用してサブプロセスを作成する前に、親子プロセス間で通信するためのパイプを作成し、サブプロセスを作成します.その後、親プロセスはパイプのリードを閉じ、サブプロセスはパイプのライトを閉じます.親プロセスはパイプにデータを書き込み、子プロセスはデータを読み取ります.親プロセスがパイプのライトエンドを閉じ、サブプロセスがパイプのリードエンドを閉じることもできます.これにより、パイプは親子プロセス間の通信にも兄弟プロセス間の通信にも使用できます.
linuxでパイプを作成するには、関数pipeで行います.この関数は、呼び出しが正常に0に返され、配列に2つの新しいファイル記述子が含まれます.エラーが発生した場合は、-1を返します.
#include int pipe(int fd[2])
パイプの両端は、それぞれ記述子fd[0]およびfd[1]で記述することができる.1つのエンドは、パイプリードと呼ばれる記述子fd[0]で表される読み取りにのみ使用される.他端は書き込みにのみ使用でき、記述子fd[1]で表され、パイプ書き込み端と呼ばれる.パイプ書き込み側からデータを読み込むか、パイプ読み取り側からデータを書き込むかでエラーが発生します.
サンプルコード1:
1つのパイプで半二重通信を実現
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>

/*   */
void read_from_pipe(int fd)
{
    char message[100];
    read(fd,message,100);
    printf("read from pipe:%s",message);
}

/*   */
void write_to_pipe(int fd)
{
    char *message="Hello,pipe!
"; write(fd,message,strlen(message)+1); } int main() { int fd[2]; pid_t pid; int stat_val; if(pipe(fd)) { printf("create pipe failed!
"); exit(1); } pid=fork(); switch(pid) { case -1: printf("fork error!
"); exit(1); case 0: // close(fd[1]);// read_from_pipe(fd[0]);// exit(0); default: // close(fd[0]);// write_to_pipe(fd[1]);// wait(&stat_val);// exit(0); } return 0; }
実行結果:
pc@ubuntu:~/linux_lan/pipe$ ./pipe read from pipe:Hello,pipe! サンプルコード2:
2つのパイプラインでフルデュプレクスを実現:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>

//          
void child_rw_pipe(int readfd,int writefd)
{
   char *message1="from child process!
"; write(writefd,message1,strlen(message1)+1); char message2[100]; read(readfd,message2,100); printf("child process read from pipe:%s",message2); } // void parent_rw_pipe(int readfd,int writefd) { char *message1="from parent process!
"; write(writefd,message1,strlen(message1)+1); char message2[100]; read(readfd,message2,100); printf("parent process read pipe:%s",message2); } int main() { int pipe1[2],pipe2[2]; pid_t pid; int stat_val; printf("realize full-duplex communication:

"); if(pipe(pipe1))// 1 { printf("pipe1 failed
"); exit(1); } if(pipe(pipe2))// 2 { printf("pipe2 failed
"); exit(1); } pid=fork();// switch(pid) { case -1: printf("fork error!
"); exit(1); // case 0: close(pipe1[1]);// 1 close(pipe2[0]);// 2 child_rw_pipe(pipe1[0],pipe2[1]);// 1 , 2 exit(0); default: close(pipe1[0]);// 1 close(pipe2[1]);// 2 parent_rw_pipe(pipe2[0],pipe1[1]);// 1 , 2 wait(&stat_val); exit(0); } return 0; }

実行結果:
pc@ubuntu:~/linux_lan/pipe$ ./dual_pipe realize full-duplex communication: parent process read pipe:from child process! child process read from pipe:from parent process! 二、dup&dup 2
1.ファイル記述子:カーネル(kernel)はファイル記述子(file descriptor)を使用してファイルにアクセスします.ファイル記述子は負の整数ではありません.既存のファイルを開くか、新しいファイルを開くと、カーネルはファイル記述子を返します.ファイルの読み書きも、ファイル記述子を使用して読み書きするファイルを指定する必要があります.標準入力(standard input)のファイル記述子は0、標準出力(standard output)は1、標準エラー(standard error)は2です.この習慣はUnixカーネルの特性ではありませんが、shellや多くのアプリケーションで使用されているため、カーネルがこの習慣に従わないと、多くのアプリケーションが使用できません.POSIXはstdIN_を定義しているFILENO、stdOUT_FILENOとstdERR_FILENOは0、1、2の代わりになります.この3つのシンボル定数の定義はヘッダファイルunistdにある.h. プロセスがファイル記述子を取得する最も一般的な方法は、ネイティブサブルーチンopenまたはcreateによって取得または親プロセスから継承することです.後者の方法では、サブプロセスが親プロセスで使用されるファイルにもアクセスできます.ファイル記述子は、通常、各プロセスに対して一意です.forkサブルーチンでサブプロセスを作成すると、親プロセスのすべてのファイル記述子のコピーが取得され、forkが実行されると開きます.fcntl、dup、dup 2サブルーチンによってプロセスがコピーまたはコピーされると、同じコピープロセスが発生します.dup  dup2 #include int dup(int oldfd); int dup2(int oldfd,int newfd); dupおよびdup 2関数の呼び出しに成功するとoldfdファイル記述子のコピーが返され、失敗すると-1が返されます.異なる点は、dup関数によって返されるファイル記述子が現在使用可能なファイル記述子の最小値であり、dup 2関数はパラメータnewfdを用いて返されるファイル記述子を指定することができる.パラメータnewfdで指定したファイル記述子が開いている場合、システムはまずそれを閉じ、oldfdで指定したファイル記述子をパラメータに割り当てます.newfdがoldfdに等しい場合、dup 2はnewfdを閉じずに返します./dupプログラムクリップ*/pid=fork();if(pid=0){/*サブプロセスの標準出力*/close(1);//パイプ入力端子から標準出力dup(fd[1])execve(「exam」,argv,environ);}/*dup 2プログラムフラグメント*/pid=fork();if(pid==0){/*標準出力を閉じ、パイプ入力端子を標準出力*/dup 2にコピーする(1,fd[1]);execve(「exam」,argv,environ);}dup 2システム呼び出しはclose操作とファイル記述子コピー操作を同じ関数に統合し、操作に原子性があることを保証することがわかる.
2.サンプルコード:
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
 int main(void)
 {
     int fd, save_fd;
     char msg[] = "This is a test of dup() & dup2()
"; int test; fd = open("zhonghe.txt", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); if(fd<0) { perror("open"); exit(1); } save_fd = dup(STDOUT_FILENO); // save_fd STDOUT_FILENO, save_fd printf("save_fd=%d
",save_fd); // test=dup2(fd, STDOUT_FILENO); // STDOUT_FILENO fd , STDOUT_FILENO zhonghe.txt printf("dup2_1=%d
",test); // , zhonghe.txt close(fd); write(STDOUT_FILENO, msg, strlen(msg)); // STDOUT_FILENO zhonghe.txt , // zhonghe.txt test=dup2(save_fd, STDOUT_FILENO); // STDOUT_FILENO save_fd , printf("dup2_2=%d
",test); // , write(STDOUT_FILENO, msg, strlen(msg)); // STDOUT_FILENO close(save_fd); return 0; }
実行結果:
pc@ubuntu:~/linux_lan/pipe$ ./test_zh save_fd=4 dup2_2=1 This is a test of dup() & dup2()
ディレクトリの下にzhongheという名前を作成します.txtファイル、内容:
dup2_1=1 This is a test of dup() & dup2()
PS:一部のコードはインターネットから来ています.