Linux进程间通信—无名管道和命名管道

无名管道(pipe)

管道是linux进程间通信的一种方式,如命令ps -ef | grep ntp
无名管道的特点:
1、只能在亲缘关系进程间通信(父子或兄弟)
2、半双工(固定的读端和固定的写端)
3、是特殊的文件,可以用read、write等,只能在内存中

管道函数原型:

 #include <unistd.h> 
 int pipe(int fds[2]);

函数pipe用于创建一个无名管道,如果成功,fds[0]存放可读的文件描述符,fds[1]存放可写文件描述符,并且函数返回0,否则返回-1。

通过调用pipe获取这对打开的文件描述符后,一个进程就可以从fds[0]中读数据,而另一个进程就可以往fds[1]中写数据。当然两进程间必须有继承关系,才能继承这对打开的文件描述符。

管道不像真正的物理文件,不是持久的,即两进程终止后,管道也自动消失了。

父子进程无名管道通信(父写子读)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    int fds[2] = {0};
    pipe(fds);
    char szBuf[32] = {'\0'};
    if(fork() == 0)         //表示子进程
    {
        close(fds[1]);       //子进程关闭写
        sleep(2);         //确保父进程有时间关闭读,并且往管道中写内容
        if(read(fds[0], szBuf, sizeof(szBuf)) > 0)
            puts(szBuf);        //打印输出szBuf
        close(fds[0]);          //子关闭读
        exit(0);
    }else{                       //表示父进程
        close(fds[0]);          //父关闭读
        write(fds[1], "hello", 6);
        waitpid(-1, NULL, 0);   //等子进程关闭读
        close(fds[1]);           //父关闭写
        exit(0);
    }
    return 0;
}

运行结果:

hello

管道两端的关闭是有先后顺序的,如果先关闭写端则从另一端读数据时,read函数将返回0,表示管道已经关闭;
但是如果先关闭读端,则从另一端写数据时,将会使写数据的进程接收到SIGPIPE发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开)信号,如果写进程不对该信号进行处理,将导致写进程终止,如果写进程处理了该信号,则写数据的write函数返回一个负值,表示管道已经关闭。

命名管道(FIFO)

无名管道只能在亲缘关系的进程间通信大大限制了管道的使用,有名管道突破了这个限制,通过指定路径名的范式实现不相关进程间的通信

创建FIFO文件的函数原型:

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

返回值:创建成功,则返回0,否则-1。
pathname为要创建的FIFO文件的全路径名
mode 为文件访问权限

创建管道文件代码:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("args error\n");
        return -1;
    }
    if(mkfifo(argv[1], 0666) == -1)
    {
        perror("make fifo failed");
        return -2;
    }
    return 0;
}


yu@ubuntu:~/0126/fifo$ gcc -o fifo fifo.c
yu@ubuntu:~/0126/fifo$ ./fifo newfile
yu@ubuntu:~/0126/fifo$ ls
fifo  fifo.c  newfile
yu@ubuntu:~/0126/fifo$ ls -l
total 12
-rwxrwxr-x 1 yu yu 7404 Jan 26 04:18 fifo
-rw-rw-r-- 1 yu yu  233 Jan 26 04:18 fifo.c
prw-rw-r-- 1 yu yu    0 Jan 26 04:18 newfile

删除FIFO文件的函数原#include

#include <unistd.h>

int main()
{
    unlink("newfile");
    return 0;
}
yu@ubuntu:~/0126/fifo$ gcc -o delfifo delfifo.c

yu@ubuntu:~/0126/fifo$ ls
delfifo  delfifo.c  fifo  fifo.c  newfile

yu@ubuntu:~/0126/fifo$ ./delfifo

yu@ubuntu:~/0126/fifo$ ls
delfifo  delfifo.c  fifo  fifo.c

注意:用命令mkfifo创建,不能重复创建,用命令unlink删除

读写FIFO

非亲缘两进程间通过FIFO通信实战

1、执行mkfifo myfifo
创建命名管道FIFO文件myfifo

2、write.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fdFifo = open("myfifo", O_WRONLY);
    write(fdFifo, "hello", 6);
    close(fdFifo);
    return 0;
}
gcc -o write write.c

生成write
3、read.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define BUFSIZE 128

int main()
{
    char szBuf[BUFSIZE];
    int fdFifo = open("myfifo", O_RDONLY);
    if(read(fdFifo, szBuf, sizeof(szBuf)) > 0)
    {
        puts(szBuf);
    }
    close(fdFifo);

    return 0;
}
gcc -o read read.c

生成read

4、此时执行./read,进入阻塞状态

5、另开一个终端,执行./write
read执行成功,屏幕输出hello

你可能感兴趣的:(linux,通信)