PS:本人用的linux系统做的实验
1、了解有名管道通信的原理。
2、掌握有名管道的创建及使用方法。
1、有名管道可用于无亲缘关系的进程间的通信,又称为FIFO。
2、有名管道使用mkfifo()创建。
3、管道打开规则:
对于读进程:
(1)阻塞打开:阻塞直到有相应进程为写而打开该FIFO。
(2)非阻塞打开:立刻返回成功。
对于写进程:
(1)阻塞打开:阻塞直到有相应进程为读而打开该FIFO。
(2)非阻塞打开:立刻返回失败,错误码为ENXIO。
1、在磁盘文件test1中输入若干行字符串。使用mkfifo函数创建一个有名管道,以阻塞方式打开管道,通过对管道进行读、写,将磁盘文件test1的内容复制到另一文件test2中,即在test1与test2之间完成内容拷贝。
2、编译程序,并分别在两个终端里运行读端和写端程序,查看结果。
组内人员分别独立完成实验
思路简述:在本实验中写端进程先通过mkfifo函数创建一个有名管道,在成功创建以后,使用open()函数以阻塞的方式打开管道,然后用open()函数以只读的方式打开test1txt文件,然后使用read函数将文件描述符的值为data_fd的文件(即test1.txt)中的内容写到buffer数组中,最后使用write函数将将buffer数组中的内容写到管道中,关闭管道和test1.txt的文件描述符。
读端进程先使用open()函数以阻塞的方式打开管道,然后用open()函数以只写的方式打开test2.txt文件,然后使用read函数将管道中的内容写到buffer数组中,最后使用write函数将将buffer数组中的内容写到test2.txt中,关闭管道和test2.txt的文件描述符。
w.c//写端程序
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
const char *fifo_name = "/tmp/my_fifo";
int pipe_fd = -1;
int data_fd = -1;
int res = 0;
const int open_mode = O_WRONLY;//阻塞打开,阻塞直到有相应进程为读而打开该FIFO。
int bytes_sent = 0;
char buffer[PIPE_BUF + 1];
int bytes_read = 0;
if(access(fifo_name, F_OK) == -1)
{
printf ("Create the fifo pipe.\n");
res = mkfifo(fifo_name, 0777);//创建管道并设置权限
if(res != 0)
{
fprintf(stderr, "Could not create fifo %s\n", fifo_name);
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIFO O_WRONLY\n", getpid());//获得写进程的进程号
pipe_fd = open(fifo_name, open_mode);//以阻塞的方式打开管道,并返回文件描述符
printf("Process %d is linked with %d\n", getpid(), pipe_fd);
if(pipe_fd != -1)
{
bytes_read = 0;
data_fd = open("test1.txt", O_RDONLY);//以只读的方式打开test1文件,并返回文件描述符
if (data_fd == -1)
{
close(pipe_fd);
fprintf (stderr, "Open file test1.txt failed\n");
return -1;
}
bytes_read = read(data_fd, buffer, PIPE_BUF);//将文件描述符的值为data_fd的文件(此处即test1.txt)中的内容写到buffer数组中,读入PIPE_BUF个字节
buffer[bytes_read] = '\0';
while(bytes_read > 0)
{
res = write(pipe_fd, buffer, bytes_read);//将buffer数组中的内容写到管道中
if(res == -1)
{
fprintf(stderr, "Write error on pipe\n");
exit(EXIT_FAILURE);
}
bytes_sent += res;
bytes_read = read(data_fd, buffer, PIPE_BUF);
buffer[bytes_read] = '\0';
}
close(pipe_fd);
close(data_fd);
}
else
exit(EXIT_FAILURE);
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}
r.c//读端程序
#include
#include
#include
#include
#include
#include
#include
int main()
{
const char *fifo_name = "/tmp/my_fifo";
int pipe_fd = -1;
int data_fd = -1;
int res = 0;
int open_mode = O_RDONLY;//阻塞打开,阻塞直到有相应进程为写而打开该FIFO。
char buffer[10];
int bytes_read = 0;
int bytes_write = 0;
memset(buffer,' ', sizeof(buffer));
printf("Process %d opening FIFO O_RDONLY\n", getpid());
pipe_fd = open(fifo_name, open_mode);
data_fd = open("test2.txt", O_WRONLY);//以只写的方式打开test2.txt文件,data_fd指向test2.txt文件
if (data_fd == -1)
{
fprintf(stderr, "Open file test2.txt failed\n");
close(pipe_fd);
return -1;
}
printf("Process %d is linked with pipe_fd: %d\n",getpid(), pipe_fd);
if(pipe_fd != -1)
{
res = read(pipe_fd, buffer, PIPE_BUF);//将管道中的内容读到buffer中
printf("Process %d reads \n'%s' from fifo\n",getpid(),buffer);
bytes_write = write(data_fd, buffer, res);将buffer的内容写入test2.txt文件中
close(pipe_fd);
close(data_fd);
}
else
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}
①在/home/mj的目录下创建test1.txt文件并写入以下内容
③运行读端程序,写端解除阻塞,将test1.txt文件中的内容写到管道中,读端也解除阻塞,读出管道中的内容并打印,同时将内容写到test2.txt中
④可以看到,我们通过有名管道实现了将test1.txt的文件内容复制到test2.txt中
无名管道只能在父子进程之间进行通信,有名管道提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,并且其打开方式与打开一个普通文件是一样的,这样即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,任意两个进程通过 FIFO 都能交换数据。要注意FIFO的内容不在磁盘中,而是在内存中。有名管道的本质是文件,FIFO同样有文件描述符,同样可以使用open/write/read等函数,明白这一点的话的话编程就容易很多了。