前一節學習了無名管道,這節學習命名管道。
二命名管道
無名管道只能用來在父子進程或兄弟進程之間進行通信,這就給沒有親緣關係的進程之間數據的交換帶來了麻煩,解決這個問題就是本節要學習的另一種管道通信:命名管道。
命名管道也被稱爲FIFO文件,FIFO不同於管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存在於文件系統中。這樣,即使與FIFO的創建進程不存在親緣關係的進程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進程以及FIFO的創建進程之間),因此,通過FIFO不相關的進程也能交換數據。值得注意的是,FIFO嚴格遵循先進先出(first in first out),對管道及FIFO的讀總是從開始處返回數據,對它們的寫則把數據添加到末尾。它們不支持諸如lseek()等文件定位操作。
http://blog.csdn.net/xiaoliangsky/article/details/40121893
1 mkfifo
int mkfifo(const char *pathname, mode_t mode);
mafifo函數創建一個FIFO,FIFO在文件系統中表現爲一個文件。
pahtname 文件路徑
mode 和系統調用open函數中的mode是一樣的。
返回值
如果函數調用成功返回非-1;
函數調用失敗返回-1。
2 命名管道操作
FIFO在文件系統中表現爲一個文件,大部分的系統文件調用都可以用在FIFO上面,比如:read,open,write,close,unlink,stat等函數。但是seek等函數不能對FIFO調用。
2.1 打開命名管道
可以調用open函數打開命名管道,但是有兩點要注意
1)不能以O_RDWR模式打開命名管道FIFO文件,否則其行爲是未定義的,管道是單向的,不能同時讀寫;
2)就是傳遞給open調用的是FIFO的路徑名,而不是正常的文件
打開FIFO文件通常有四種方式:
open(pathname, O_RDONLY);//1只讀、阻塞模式
open(pathname, O_RDONLY | O_NONBLOCK);//2只讀、非阻塞模式
open(pathname, O_WRONLY);//3只寫、阻塞模式
open(pathname, O_WRONLY | O_NONBLOCK);//只寫、非阻塞模式
注意阻塞模式open打開FIFO:
1)當以阻塞、只讀模式打開FIFO文件時,將會阻塞,直到其他進程以寫方式打開訪問文件;
2)當以阻塞、只寫模式打開FIFO文件時,將會阻塞,直到其他進程以讀方式打開文件;
3)當以非阻塞方式(指定O_NONBLOCK)方式只讀打開FIFO的時候,則立即返回。當只寫open時,如果沒有進程爲讀打開FIFO,則返回-1,其errno是ENXIO。
下面是一個命名管道的例子:
用命名管道實現多個進程間的通信,一個server進程負責接受多個cilent進程發來的消息
server.c代碼:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/stat.h>
typedef struct
{
pid_t child_pid;
char message[PIPE_BUF+1];
}fifo_message;
int main()
{
int fd;
const char *fifoname;
fifo_message msgbuf;
fifoname = "/tmp/serverfifo";
if (access(fifoname, F_OK) == -1)
{
if (mkfifo(fifoname, 0666) == -1)
{
perror("mkfifo error\n");
exit(-1);
}
}
if ((fd = open(fifoname, O_RDONLY)) == -1)//以只讀、阻塞模式打開
{
fprintf(stdout, "open %s failed\n", fifoname);
exit(-1);
}
while (1)
{
if (read(fd, &msgbuf, sizeof(msgbuf)) < 0)
{
close(fd);
perror("read error\n");
exit(-1);
}
fprintf(stdout, "message from child: %d, message: %s\n", msgbuf.child_pid, msgbuf.message);
sleep(1);
}
return 0;
}
client.c的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
struct fifo_message
{
pid_t child_pid;
char message[PIPE_BUF+1];
};
int main()
{
int fd;
const char *fifoname;
struct fifo_message msgbuf;
fifoname = "/tmp/serverfifo";
if (access(fifoname, F_OK) == -1)
{
perror("access error\n");
exit(-1);
}
if ((fd = open(fifoname, O_WRONLY)) < 0)//以只寫、阻塞模式打開
{
perror("open error\n");
}
msgbuf.child_pid = getpid();
while (1)
{
printf("input the message: ");
if (fgets(msgbuf.message, sizeof(msgbuf.message), stdin) == NULL)
{
perror("fgets error or end\n");
break;
}
msgbuf.message[strlen(msgbuf.message)] = '\0';
if (write(fd, &msgbuf, sizeof(msgbuf)) == -1)
{
perror("write error\n");
close(fd);
exit(-1);
}
}
close(fd);
return 0;
}
運行結果: