basic concept of piping
Pipelines are the oldest form of interprocess communication in UNIX.
We refer to a data flow from one process to another as a "pipe"
such as: PS aux | grep httpd | awk ' {print $} '
Pipeline
The nature of the pipeline
Fixed-size kernel buffers
Pipe limits
1) The pipe is half-duplex , the data can only flow in one direction, need to establish two pipelines when the two sides communicate;
2) Anonymous pipelines can only be used to communicate between processes that have a common ancestor, such as a parent process and a child process that is forked out; [Typically, a pipeline is created by a process, and then the process calls fork, and then the parent-child process shares the pipeline]
Anonymous piping pipe
Synopsis #include <unistd.h> int pipe (int pipefd[2]);
Function
Create a nameless pipe
Parameters
PIPEFD: An array of file descriptors, where pipefd[0] represents the read end, Pipefd[1] represents the write end
Pipeline creation
Implement its own pipeline void Err_exit (string str); int main () {int pipefd[2]; if (pipe (PIPEFD) = =-1) err_exit ("Pipe error"); pid_t pid; if (PID = fork ()) < 0) err_exit ("fork Error"); if (PID = = 0)//in Child, Write pipe {close (pipefd[0]); Make Stdout_fileno also point to pipefd[1], that is, the output of the LS command will be printed to the pipeline dup2 (Pipefd[1],stdout_fileno); You can close the pipe write end close (pipefd[1]) at this time; EXECLP ("/bin/ls", "/bin/ls", NULL); If the process image substitution fails, print the following error message fprintf (stderr, "CHILD:EXECLP error"); Exit (0); }//in Parent Close (pipefd[1]); Make Stdin_fileno also point to pipefd[2], that is, the WC command will read the input dup2 (Pipefd[0],stdin_fileno) from the pipeline; At this point close (pipefd[0]) can be closed at the end of pipe reading; EXECLP ("/USR/BIN/WC", "/USR/BIN/WC", "-w", NULL); If the process image substitution fails, print the following error message fprintf (stderr, "PARENT:EXECLP error"); return 0;} void Err_exit (String str) {perror (Str.c_str ()); Exit (exit_failure);}
Example : piping programming practice
void Err_exit (string str); int main () { int pipefd[2]; int ret; if (ret = pipe (PIPEFD))! = 0) { err_exit ("pipe error"); } pid_t pid = fork (); if (PID = =-1) { err_exit ("fork Error"); } if (PID = = 0) //in Child, Write pipe { close (pipefd[0]); Close Read pipe string str ("I Can Write pipe from child!"); Write (Pipefd[1],str.c_str (), str.size ()); Write to Pipe close (pipefd[1]); Exit (0); } In Parent, Read pipe Close (pipefd[1]); Close Write Pipe char buf[1024]; memset (buf,0,sizeof (BUF)); Read (pipefd[0],buf,sizeof (BUF)); Read from pipe cout << "Read from pipe:" << buf << Endl; Close (pipefd[0]); return 0;} void Err_exit (String str) { perror (str.c_str ()); Exit (exit_failure);}
Anonymous pipe Read and write rules
1) When the pipe is empty
O_nonblock the Disable:read call is blocked , that is, the process pauses execution until the data arrives.
The O_nonblock enable:read call returns a -1,errno value of eagain.
2) when the pipe is full
O_nonblock Disable:write Call blocked until a process reads the data.
O_nonblock Enable: Call returns -1,errno value of Eagain
3) The pipe is constantly written, full
O_nonblock Disable:write Call blocking (block)
O_nonblock Enable: Call returns -1,errno value of Eagain
Example: Set parent process unblock read Pipeint main () {int pipefd[2]; int ret; if (ret = pipe (PIPEFD))! = 0) {err_exit ("pipe error"); } pid_t pid = fork (); if (PID = =-1) {Err_exit ("fork Error"); } if (pid = = 0)//in Child, Write pipe {sleep (10); Close (pipefd[0]); Close Read Pipe String str ("I Can Write pipe from child!"); Write (Pipefd[1],str.c_str (), str.size ()); Write to pipe close (pipefd[1]); Exit (0); }//in Parent, Read pipe Close (pipefd[1]); Close Write Pipe Char buf[1024]; memset (buf,0,sizeof (BUF)); Set Read PIPEFD unblock! int flags = FCNTL (PIPEFD[0],F_GETFL); Flags |= O_nonblock; ret = Fcntl (pipefd[0],f_setfl,flags); if (ret! = 0) {err_exit ("Set UnBlock error"); } int readcount = Read (pipefd[0],buf,sizeof (BUF)); Read from Pipe if (Readcount < 0) {//read returns immediately, no longer waits for the child process to send data err_exit ("read error"); } cout << "READ from pipe: "<< buf << Endl; Close (pipefd[0]); return 0;}
4) If the file descriptor for all the pipe writes is closed, read returns 0
int main () { int pipefd[2]; int ret; if (ret = pipe (PIPEFD))! = 0) { err_exit ("pipe error"); } pid_t pid = fork (); if (PID = =-1) { err_exit ("fork Error"); } if (PID = = 0) //in child {//close all close (pipefd[0]); Close (pipefd[1]); Exit (0); } In Parent sleep (1); Close (pipefd[1]); Close Write Pipe, now all PIPEFD[1] Closed!!! Char buf[1024]; memset (buf,0,sizeof (BUF)); int readcount = Read (pipefd[0],buf,sizeof (BUF)); Read from pipe if (Readcount = = 0) { cout << "OK, read 0 byte" << endl; } Close (pipefd[0]); return 0;}
5) if the file descriptor corresponding to all the pipe reads is closed, the write operation generates a signal
void onsignalaction (int signalnumber) {switch (signalnumber) {case Sigpipe:cout << receive signal Sigpipe: "<< signalnumber << Endl; Break Default:cout << "Other signal" << Endl; Break }}int Main () {if (signal (sigpipe,onsignalaction)! = 0) {err_exit ("signal error"); } int pipefd[2]; int ret; if (ret = pipe (PIPEFD))! = 0) {err_exit ("pipe error"); } pid_t pid = fork (); if (PID = =-1) {Err_exit ("fork Error"); } if (pid = = 0)//in Child, Write pipe {//wait Parent Close pipefd[0] sleep (1); Close (pipefd[0]); String str ("I Can Write Pipe from child!"); Write (Pipefd[1],str.c_str (), str.size ()); Write to pipe close (pipefd[1]); Exit (0); }//in Parent, close all Pipe close (pipefd[1]); Close (pipefd[0]); Wait (NULL); return 0;}
Linux Pipe Features
1) When the amount of data to be written is not greater than pipe_buf , Linux guarantees the atomicity of the write.
2) Linux will no longer guarantee the atomicity of writes when the amount of data to be written is greater than pipe_buf.
Example: Test pipe_buf size int main () { int pipefd[2]; int ret = pipe (PIPEFD); if (Ret < 0) { err_exit ("pipe error"); } int flags = FCNTL (PIPEFD[1],F_GETFL); Flags |= O_nonblock; ret = Fcntl (pipefd[1],f_setfl,flags); if (Ret < 0) { err_exit ("Fcntl error"); } Write Test unsigned int countfortestpipe = 0; while (true) { ret = write (pipefd[1], "a", 1); if (Ret < 0) {break ; } + + countfortestpipe; } cout << "size =" << countfortestpipe << Endl;} /** test results: Ubuntu 14.04 X64 [email protected]:~/apue/it$./main size = 65536*/
Attached-Pipeline capacity query
Man 7 pipe
Attached-deep understanding of file descriptors
int main () { close (Stdin_fileno); if (Open ("Readfile.txt", o_rdonly) = =-1) { err_exit ("Open read error"); } Close (Stdout_fileno); if (Open ("Writefile.txt", o_wronly| o_trunc| o_creat,0644) = =-1) { err_exit ("Open write Error"); } if (EXECLP ("/bin/cat", "/bin/cat", NULL) = =-1) { err_exit ("EXECLP error"); } return 0;}
Linux pipelines (anonymous pipe)