linux进程间通信——有名管道

linux进程间通信——有名管道

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文件并写入以下内容
linux进程间通信——有名管道_第1张图片

②运行写端程序,由于此时并未打开读端程序,所以写端程序阻塞
linux进程间通信——有名管道_第2张图片

③运行读端程序,写端解除阻塞,将test1.txt文件中的内容写到管道中,读端也解除阻塞,读出管道中的内容并打印,同时将内容写到test2.txt中
linux进程间通信——有名管道_第3张图片

④可以看到,我们通过有名管道实现了将test1.txt的文件内容复制到test2.txt中
linux进程间通信——有名管道_第4张图片

八、实验总结

无名管道只能在父子进程之间进行通信,有名管道提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,并且其打开方式与打开一个普通文件是一样的,这样即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,任意两个进程通过 FIFO 都能交换数据。要注意FIFO的内容不在磁盘中,而是在内存中。有名管道的本质是文件,FIFO同样有文件描述符,同样可以使用open/write/read等函数,明白这一点的话的话编程就容易很多了。

你可能感兴趣的:(linux,服务器,网络,c语言)