FIFO(也称为有名管道)是first in first out的意思,也就是队列的特点。有名管道也是一个单向的数据流,但它与管道又有写区别。有名管道是有名字的,每一个FIFO对应于一个路径名,正因为这一点,有名管道可以允许非亲缘关系的进程访问同一个FIFO。另外,有名管道存在于磁盘当中,而管道存在于内存当中,通信结束后,有名管道的文件本身仍热存在,但是管道已经释放了。有名管道与文件也是有区别的,文件的话,当读取其中的内容之后,信息依然存在,但是有名管道中,通信结束之后,信息就会丢失。 有名管道的使用是得首先通过mkfifo()函数创建一个fifo,然后通过open()、write()、read()等函数进行操作,当最后使用完时,可以调用unlink()函数对fifo文件进行删除。
下面先看一个有名管道的简单应用程序:
- /*fifo.c*/
- #include <stdio.h>
-
#include <unistd.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
#define FIFO_NAME "fifo_test"
-
#define MAX 80
-
-
int main()
-
{
-
pid_t pid;
-
int fd;
-
char buf[MAX]={0};
-
-
unlink(FIFO_NAME); //为了防止FIFO_NAME文件存在
-
mkfifo(FIFO_NAME, 0744); //创建fifo
-
pid = fork();
-
if(pid == 0) {
-
fd = open(FIFO_NAME, O_RDONLY);
-
while(read(fd, buf, MAX) != 0) {
-
printf("read from fifo:%s\n", buf);
-
}
-
close(fd);
-
} else if(pid > 0) {
-
fd = open(FIFO_NAME, O_WRONLY);
-
while(fgets(buf, MAX, stdin) != NULL) {
-
buf[strlen(buf)-1] = 0; //deal with enter key
-
write(fd, buf, MAX);
-
}
-
close(fd);
-
wait(NULL); //等待子进程退出
-
unlink(FIFO_NAME);
-
} else {
-
perror("fork error");
-
exit(1);
-
}
-
-
return 0;
-
}
这个程序的一次执行结果如下:
- ^_^[sunny@sunny-laptop ~/summer]121$ ./a.out
-
sun //从键盘输入
-
read from fifo:sun
-
ls //从键盘输入
-
read from fifo:ls
-
open //从键盘输入
-
read from fifo:open
-
lovelinux //从键盘输入
-
read from fifo:lovelinux //显示完毕之后,键入ctrol+D结束
-
^_^[sunny@sunny-laptop ~/summer]122$
程序说明:这个程序中,创建了一个进程,父进程以写的方式打开fifo,循环从键盘接收输入的字符串,之后去掉“\n”,将键盘接收到的字符串写入fifo中。对于子进程,以只读的方式打开fifo文件,之后从中读取写入的字符数据。这里应当注意一下:fifo写入的时候是写到fifo的末尾,读取的时候是从fifo的开始进行读取,而且fifo进行读写操作的时候,只有读端和写端同时都打开的时候才能进行相应的操作,否则,读取端和写入端都会陷入等待状态,并且有可能发生死锁状态,这点切记。
下面,进入我们的正题——通过有名管道实现无亲缘关系的客户与服务器模型。
下面的这个程序也是比较简单,不过不用急,我们慢慢对代码进行修改,由简单变复杂。这个程序主要是实现没有亲缘关系的两个进程进行通信,其中的client进程向fifo中循环写入数据,而在另外一个终端中运行的server进程,循环从fifo中读取数据并且显示出来。
- /*fifo_server.c*/
- #include <stdio.h>
-
#include <unistd.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
#define FIFO_NAME "fifo_test"
-
#define MAX 1024
-
-
int main()
-
{
-
int fd;
-
char buf[MAX]={0};
-
-
fd = open(FIFO_NAME, O_RDONLY);
-
while(read(fd, buf, MAX) != 0) {
-
printf("read from client:%s\n", buf);
-
}
-
-
return 0;
-
}
- /*fifo_client.c*/
- #include <stdio.h>
-
#include <unistd.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
#define FIFO_NAME "fifo_test"
-
#define MAX 1024
-
-
int main()
-
{
-
int fd;
-
char buf[MAX]={0};
-
-
unlink(FIFO_NAME);
-
mkfifo(FIFO_NAME, 0744);
-
fd = open(FIFO_NAME, O_WRONLY);
-
while(fgets(buf, MAX, stdin) != NULL) {
-
buf[strlen(buf)-1] = 0; //是为了去掉回车符
-
write(fd, buf, MAX);
-
}
-
unlink(FIFO_NAME);
-
printf("connect over,exit successfully!\n");
-
return 0;
-
}
编译这两个程序:
- O_O[sunny@sunny-laptop ~/summer/fifo_rw]11$ gcc fifo_server.c -o server
-
^_^[sunny@sunny-laptop ~/summer/fifo_rw]12$ gcc fifo_client.c -o client
在一个终端执行:
- ^_^[sunny@sunny-laptop ~/summer/fifo_rw]13$ ./client
- sun //输入的数据
- open //输入的数据
- connect over,exit successfully!
- ^_^[sunny@sunny-laptop ~/summer/fifo_rw]14$
在另外一个终端执行:
- ^_^[sunny@sunny-laptop ~/summer/fifo_rw]2$ ./server
- read from client:sun
- read from client:open
这个简单的例子是半双工通信。为了实现全双工通信,我们需要两个fifo。程序代码如下:
- /*fifo_client.c*/
-
#include <stdio.h>
-
#include <unistd.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
#define FIFO_NAME1 "fifo_test1"
-
#define FIFO_NAME2 "fifo_test2"
-
#define MAX 1024
-
-
int main()
-
{
-
int fd1, fd2;
-
char buf[MAX]={0};
-
-
unlink(FIFO_NAME1);
-
unlink(FIFO_NAME2);
-
mkfifo(FIFO_NAME1, 0744);
-
mkfifo(FIFO_NAME2, 0744);
-
fd1 = open(FIFO_NAME1, O_WRONLY);
-
fd2 = open(FIFO_NAME2, O_RDONLY);
-
while(fgets(buf, MAX, stdin) != NULL) {
-
buf[strlen(buf)-1] = 0; //是为了去掉回车符
-
write(fd1, buf, MAX);
-
read(fd2, buf, MAX);
-
printf("client read from server:%s\n", buf);
-
}
-
unlink(FIFO_NAME1);
-
unlink(FIFO_NAME2);
-
printf("connect over,exit successfully!\n");
-
return 0;
-
}
- /*fifo_server.c*/
-
#include <stdio.h>
-
#include <unistd.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
#define FIFO_NAME1 "fifo_test1"
-
#define FIFO_NAME2 "fifo_test2"
-
#define MAX 1024
-
-
int main()
-
{
-
int fd1, fd2;
-
char buf[MAX]={0};
-
-
fd1 = open(FIFO_NAME1, O_RDONLY);
-
fd2 = open(FIFO_NAME2, O_WRONLY);
-
while(read(fd1, buf, MAX) != 0) {
-
printf("read from client:%s\n", buf);
-
fgets(buf, MAX, stdin);
-
buf[strlen(buf)-1] = 0;
-
write(fd2, buf, MAX);
-
}
-
-
return 0;
-
}
编译并运行这个全双工通信的例子:
编译链接:
- ^_^[sunny@sunny-laptop ~/summer/fifo_rw1]96$ gcc fifo_client.c -o client
-
^_^[sunny@sunny-laptop ~/summer/fifo_rw1]97$ gcc fifo_server.c -o server
执行客户端(client):
- ^_^[sunny@sunny-laptop ~/summer/fifo_rw1]98$ ./client
-
hello world //从键盘输入
-
client read from server:hello who are you?
-
I am sunny. //从键盘输入
-
client read from server:Oh
-
bye //从键盘输入
-
client read from server:bye
-
connect over,exit successfully!
-
^_^[sunny@sunny-laptop ~/summer/fifo_rw1]99$
执行服务器端(server):
- ^_^[sunny@sunny-laptop ~/summer/fifo_rw1]5$ ./server
-
read from client:hello world
-
hello who are you? //从键盘输入
-
read from client:I am sunny.
-
Oh //从键盘输入
-
read from client:bye
-
bye //从键盘输入ctrol+d
-
^_^[sunny@sunny-laptop ~/summer/fifo_rw1]6$
程序说明:这两个程序先执行client之后,再启动server(否则会发生一些问题,大家可以试验一下)。之后现在client端输入数据,转到server端发现从中读取了数据,紧接着在server端输入,就这样循环着,呵呵......
阅读(2295) | 评论(0) | 转发(0) |