Linux下进程间通信方式——pipe(管道)
先看这一篇文章
Linux下进程间通信方式——pipe(管道) - cs_wu - 博客园
结合<<understanding unix/linux programming>>
这本书的第10章:IO重定向与管道
,我希望写出如下的代码,
- popen,运行子进程,并与子进行进行通信
- 向子进程写入数据,对他进行读取
- 得到子进程的输出信息,与error信息
前置的知识
linux api
pipe
dup2
fcntl
eecvp
1
2
3
4
2
3
4
管道(pipe)读写的4种情况
plaintext
write +---------+ read
-------->| Pipe |--------->
+---------+
1
2
3
4
2
3
4
- read端如果一直在读,write端不写,会阻塞
- write端如果一直在写,read端不读,会阻塞
- read端如果一直在读,write端写了一部分,然后关闭了,read会读取到EOF,相当于文件的末尾
- write端如果一直在写,read端读了一部分,然后关闭了,write端会得到
SIGPIPE
信号
代码
注意看相应的代码
- 利用
execvp
调用另一个程序
sample.cpp
cpp
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <wait.h>
using T = char * const;
char * __argv[100] = {
"ls","-l",NULL
};
int wait_child_exit(int pid){
int status;
int ret = -1;
while ( 1 ) {
ret = waitpid(pid, &status, WNOHANG);
if( ret == -1) break;
if( ret == 0) continue;
return pid;
}
return ret;
}
int main(){
int input_pipe_fd[2]; //写管道
int output_pipe_fd[2];//读管道
int ret = pipe(input_pipe_fd);
if( ret == -1){
std::cerr << "input_pipe_fd create failed" << "\n";
return -1;
}
ret = pipe(output_pipe_fd);
if( ret == -1){
std::cerr << "output_pipe_fd create failed" << "\n";
return -1;
}
int pid = fork();
auto set_fd_no_close_on_exec = [](int fd){
int flags = fcntl(fd,F_GETFD,0);
fcntl(fd, F_SETFD,flags & (~FD_CLOEXEC));
};
if(pid == 0){ // child
close(output_pipe_fd[0]); //关闭 output的 读端
close(input_pipe_fd[1]); //关闭 intput的 写端
// dup2(input_pipe_fd[0], 0);
dup2(output_pipe_fd[1], 1); //重定向写
set_fd_no_close_on_exec(input_pipe_fd[0]);
set_fd_no_close_on_exec(0);
dup2(output_pipe_fd[1], 1);
set_fd_no_close_on_exec(output_pipe_fd[1]);
set_fd_no_close_on_exec(1);
//执行
execvp("ls",__argv);
}
else { // parent
close(output_pipe_fd[1]); //关闭 output的 写端
close(input_pipe_fd[0]); //关闭 intput的 读端
//读取数据
char buf[128];
while ( 1 ) {
int readn = read(output_pipe_fd[0], buf, sizeof(buf));
if(readn <= 0) break;
for(int i=1;i<=readn;++i){
std::cout << buf[i-1];
}
}
int ret = wait_child_exit(pid);
std::cout << "wait child exit ret id: "
<< ret
<< "\n";
std::cout << "\n main process exit " << "\n";
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
- 测试通信之间的时间间隔问题
sample_1.cpp
cpp
// delay
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <wait.h>
using T = char * const;
char * __argv[100] = {
"ls","-l",NULL
};
int wait_child_exit(int pid){
int status;
int ret = -1;
while ( 1 ) {
ret = waitpid(pid, &status, WNOHANG);
if( ret == -1) break;
if( ret == 0) continue;
return pid;
}
return ret;
}
int main(){
int input_pipe_fd[2]; //写管道
int output_pipe_fd[2];//读管道
int ret = pipe(input_pipe_fd);
if( ret == -1){
std::cerr << "input_pipe_fd create failed" << "\n";
return -1;
}
ret = pipe(output_pipe_fd);
if( ret == -1){
std::cerr << "output_pipe_fd create failed" << "\n";
return -1;
}
int pid = fork();
auto set_fd_no_close_on_exec = [](int fd){
int flags = fcntl(fd,F_GETFD,0);
fcntl(fd, F_SETFD,flags & (~FD_CLOEXEC));
};
if(pid == 0){ // child
close(output_pipe_fd[0]); //关闭 output的 读端
close(input_pipe_fd[1]); //关闭 intput的 写端
// dup2(input_pipe_fd[0], 0);
dup2(output_pipe_fd[1], 1); //重定向写
set_fd_no_close_on_exec(input_pipe_fd[0]);
set_fd_no_close_on_exec(0);
dup2(output_pipe_fd[1], 1);
set_fd_no_close_on_exec(output_pipe_fd[1]);
set_fd_no_close_on_exec(1);
//执行
const char * child_message = "hello world !";
for(int i=1;i<=3;++i){
// std::cout << "print " << i << " times" << std::endl;
// std::endl 会把c++ 输出缓存的内容fflush
write(1,child_message , strlen(child_message));
sleep(1);
}
// https://unix.stackexchange.com/a/430371
// fd will automatically closed when process terminates
return 0;
}
else { // parent
close(output_pipe_fd[1]); //关闭 output的 写端
close(input_pipe_fd[0]); //关闭 intput的 读端
//读取数据
char buf[128];
char message_buf[128];
while ( 1 ) {
int readn = read(output_pipe_fd[0], buf, sizeof(buf));
//std::cout << "\n===> readn bytes : " << readn << "\n";
sprintf(message_buf, "\n===> readn %d bytes.\n",readn);
write(1, message_buf, strlen(message_buf));
if(readn <= 0) break;
// for(int i=1;i<=readn;++i){
// std::cout << buf[i-1];
// }
write(1, buf, readn);
}
int ret = wait_child_exit(pid);
std::cout << "wait child exit ret id: "
<< ret
<< "\n";
std::cout << "\n main process exit " << "\n";
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104