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

Linux进程间通讯(IPC)------匿名管道

2016-07-16 14:33 435 查看


匿名管道的特点

数据是字节流。
当从一个管道中读取数据时,除非一端写入数据或写端关闭,否则会处于阻塞状态。
管道是单传输的,只能一端用于写,一端用于读,即是半双工的。
管道只能在具有相同祖先的进程间进行通讯。
当写入的数据小于PIPE_BUF字节时,那么写入操作是原子性的(就是要么全部数据连续写入,要么一个字节都没有写入)。这样可以确保多个进行写一个管道时,出现数据混乱问题。
管道容量有限制。当写入的数据超过容量时,写入操作会阻塞,直到另一端读出一些数据,当写完所有数据才能返回。因此为了避免阻塞,只能加快读的速度。
管道的读和写默认是阻的态,可以使用fcntl函数将管道的读写操作设为非阻塞状态。
对于读和写关闭时造成的影响

如果所有的读描述符都关闭情况下,进行write操作,将返回SIGPIPE信号
如果所有的写描述都关闭情况下,进行read操作,将返回0

对于read读取缓冲区为空,阻塞和非阻塞的情况

阻塞:read读取的缓存区为空,会阻塞read操作,知道有数据写入
非阻塞:read操作会立即返回-1,errno会返回EAGIN.

对write写缓存区满时,阻塞和非阻塞的情况
阻塞:write操作将阻塞,直到有程序将缓冲区的数据取走,write写入完所有数据。
非阻塞:write操作会立即返回-1,errno会返回EAGIN。

匿名管道相关函数

       1.创建管道,函数原型如下:

     int pipe(int filedes[2]);

           说明:返回值为int类型,0表示创建成功,-1表示创建失败。参数为2个文件描述符,fd[0]表示读描述符,fd[1]表示写描述符。
    
       2.dup和dup2函数
          可以使用dup和dup2函数复制描述符、

     int dup(int oldfd);

           说明:该函数用于复制oldfd描述符,返回一个新的最小的描述符。

     int dup(int oldfd, int newfd);

           说明:该函数用oldfd描述符,覆盖newfd描述符。
    
        3.popen函数

     FILE *popen(const char *command, const char* mode):
     int pclose(FILE *stream);

           说明: popen函数创建一个子进程才执行shell,而shell又创建一个子进程来执行command。
           功能:该函数用于和shell命令通讯。
           注意:popen使用的是块缓存,因此,一般调用进程向管道写入数据,stdio库不会立即将数据传递给另一端,除非手动调用fflush和fclose。因此对于从管道中读数据,如果对端正在操作stdio,那么命令进程写的数据不会立即传送,这种对于调用进程没有办法立即读取数据。

例子

        一个父子进程通过匿名管道进行通讯的例子。    

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
int fd[2];
char buffer[1024] = {0};
char str[] = "Hello world!";

int ret = pipe(fd);
if(ret ==-1)
{
printf("创建管道失败\n");
return -1;
}

pid_t pid = fork();
switch(pid)
{
case 0:
close(fd[1]);
read(fd[0], buffer, sizeof(buffer));
printf("子进程接收到数据: %s\n", buffer);
break;
case -1:
printf("创建进程失败\n");
break;
default:
close(fd[0]);
write(fd[1], str, strlen(str));
sleep(5);//等待子进程先于父进程结束
break;
}

return 0;
}

        输出结果如下:

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