一.介绍
在前面的无名管道博文中,我们看到了创建两个管道可以实现进程间的全双工通信,那么同样也可以创建两个FIFO(有名管道)来实现不同进程间的全双工通信。
1.为什么引入有名管道?
我们通常所说的管道为无名管道或者匿名管道,管道没有名字,因此,只能在有亲缘关系的进程间(父子进程)实现通信,有名管道的出现突破了该限制,它是一个设备文件,它提供一个路径名与FIFO关联,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问这个路径也可以实现通信。
2.创建有名管道
mknod/mkfifo
shell中的创建方式
mknod 名字 pipe
mkfifo 名字
函数创建方式
(1)
int mknod(const char *path, mode_t mode, dev_t dev);
参数mode的选择
Name Description
S_IFIFO FIFO-special
S_IFCHR Character-special (non-portable)
S_IFDIR Directory (non-portable)
S_IFBLK Block-special (non-portable)
S_IFREG Regular (non-portable)
If mode is not S_IFIFO or dev is not 0, the behavior of mknod() is unspecified.
举例:
mknod("/tmp/fifo", S_IFIFO | 0666, 0)
(2)
int mkfifo(const char *pathname, mode_t mode);
mkfifo() makes a FIFO special file with name pathname. mode specifies the FIFO's permissions.
所以只需要填写管道的权限就型
举例
mkfifo("/tmp/fifo", 0666);
3.使用有名管道
与无名管道的使用方法基本相同,只是需要先调用open函数将其打开。因为有名管道终究是在硬盘上的文件,而无名管道只是存在内存上的特殊文件。
注意open()的阻塞情况
1.以只写方式打开,阻塞直到有读方式打开管道
open(“/tmp/fifo”, O_WRONLY);
2.以只读方式打开,阻塞直到有写方式打开管道
open(“/tmp/fifo”, O_RDONLY);
3.同时读写方式打开,一定不阻塞。
open(“/tmp/fifo”, O_RDWR);
二.代码演示
1.server.c
#include"utili.h"
int main()
{
char sendbuf[MAX_MSG_LEN];
char recvbuf[MAX_MSG_LEN];
int res = mkfifo(FIFO_WRITE, 0666);
if(res == -1)
{
perror("mkfifo WRITE");
exit(EXIT_FAILURE);
}
//以只写方式打开,会阻塞到有读方式打开管道
int wfd = open(FIFO_WRITE, O_WRONLY);
if(wfd == -1)
{
perror("open WRITE");
exit(EXIT_FAILURE);
}
//以只读方式打开,会阻塞到有写方式打开管道
int rfd = open(FIFO_READ, O_RDONLY);
if(rfd == -1)
{
perror("open READ");
exit(EXIT_FAILURE);
}
while(1)
{
printf("Ser:>");
scanf("%s", sendbuf);
if(strcmp(sendbuf, "quit") == 0)
{
close(wfd);
unlink(FIFO_WRITE);
close(rfd);
exit(EXIT_SUCCESS);
}
write(wfd, sendbuf, strlen(sendbuf)+1);
read(rfd, recvbuf, MAX_MSG_LEN);
printf("Cli:>%s\n", recvbuf);
}
}
2.client.c
#include"utili.h"
int main()
{
char recvbuf[MAX_MSG_LEN];
char sendbuf[MAX_MSG_LEN];
int wfd, rfd;
int res = mkfifo(FIFO_READ, 0666);
if(res == -1)
{
perror("mkfifo READ");
exit(EXIT_FAILURE);
}
//server的写对应client读
rfd = open(FIFO_WRITE, O_RDONLY);
if(rfd == -1)
{
perror("open READ");
exit(EXIT_FAILURE);
}
wfd = open(FIFO_READ, O_WRONLY);
if(wfd == -1)
{
perror("open WRITE");
exit(EXIT_FAILURE);
}
while(1)
{
read(rfd, recvbuf, MAX_MSG_LEN);
printf("Ser:>%s\n", recvbuf);
printf("Cli:>");
scanf("%s", sendbuf);
if(strcmp(sendbuf, "quit") == 0)
{
close(rfd);
unlink(FIFO_READ);
close(wfd);
exit(EXIT_SUCCESS);
}
write(wfd, sendbuf, strlen(sendbuf)+1);
}
}
3.公共头文件
utili.h
#ifndef _UTILI_H_
#define _UTILI_H_
#include<stdio.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdlib.h>
#include<string.h>
#define FIFO_READ "readfifo"
#define FIFO_WRITE "writefifo"
#define MAX_MSG_LEN 256
#endif