您的位置:首页 > 运维架构 > Linux

二十、Linux系统编程-管道(一)管道、匿名管道、管道读写规则

2015-04-11 15:45 726 查看
一、管道

概念:管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”,管道本质上是内核中一块固定大小的缓冲区
管道限制:

管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道
只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。

二、匿名管道pipe
函数声明:
#include <unistd.h>
int pipe(int pipefd[2]);
函数参数:pipefd[0]是管道读端,pipefd[1]管道写端
返回值:成功返回0,失败返回-1
创建管道示意图:



管道示例1-父子进程通信:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)

int main()
{
signal(SIGCHLD,SIG_IGN);
int pfd[2];
int fd;
char buff[1024];
if (pipe(pfd) == -1)
ERR_EXIT("pipe error");
if ((fd = fork()) < 0)
ERR_EXIT("fork error");
if (fd == 0)
{
close(pfd[0]);
write(pfd[1],"hello",5);
close(pfd[1]);
exit(EXIT_SUCCESS);
}
close(pfd[1]);
read(pfd[0],buff,5);
printf("%s\n",buff);
return 0;
}
管道示例2-数据重定向:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)

int main()
{
signal(SIGCHLD,SIG_IGN);
int pfd[2];
int fd;
char buff[1024];
if (pipe(pfd) == -1)
ERR_EXIT("pipe error");
if ((fd = fork()) < 0)
ERR_EXIT("fork error");
if (fd == 0)
{
dup2(pfd[1],STDOUT_FILENO);
close(pfd[0]);
close(pfd[1]);
execlp("ls","ls",NULL);
exit(EXIT_FAILURE);
}
dup2(pfd[0],STDIN_FILENO);
close(pfd[0]);
close(pfd[1]);
execlp("wc","wc","-w",NULL);
printf("%s\n",buff);
return 0;
}


三、管道读写规则
如果往读端写数据或者从写端读数据都会失败。

(1)、当没有数据可读时

O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。

(2)、管道满的时候

O_NONBLOCK disable:write调用阻塞,直到有进程读走数据
O_NONBLOCK enable:调用返回-1,errno值为EAGAIN

(3)、如果所有管道写端对应的文件描述符被关闭,则read返回0
(4)、如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE
(5)、当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
(6)、当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>

#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)

#define TEST_SIZE 68*1024

int main(void)
{
char a[TEST_SIZE];
char b[TEST_SIZE];

memset(a, 'A', sizeof(a));
memset(b, 'B', sizeof(b));

int pipefd[2];

int ret = pipe(pipefd);
if (ret == -1)
ERR_EXIT("pipe error");

pid_t pid;
pid = fork();
if (pid == 0)
{
close(pipefd[0]);
ret = write(pipefd[1], a, sizeof(a));
printf("apid=%d write %d bytes to pipe\n", getpid(), ret);
exit(0);
}

pid = fork();

if (pid == 0)
{
close(pipefd[0]);
ret = write(pipefd[1], b, sizeof(b));
printf("bpid=%d write %d bytes to pipe\n", getpid(), ret);
exit(0);
}

close(pipefd[1]);

sleep(1);
int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
char buf[1024*4] = {0};
int n = 1;
while (1)
{
ret = read(pipefd[0], buf, sizeof(buf));
if (ret == 0)
break;
printf("n=%02d pid=%d read %d bytes from pipe buf[4095]=%c\n", n++, getpid(), ret, buf[4095]);
write(fd, buf, ret);

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: