一文搞懂有名管道

一.有名管道

1.1有名管道特点

有名管道(Named Pipes)是一种在文件系统中有名字的特殊文件,用于进程间通信。以下是有名管道的几个特点:

  1. 有名:与无名管道不同,有名管道在文件系统中具有唯一的路径名,可以通过路径名进行访问和引用。

  2. 持久性:有名管道是持久的,与进程无关。即使创建它的进程退出,有名管道仍然存在于文件系统中,可以由其他进程打开和使用。

  3. 双向通信:有名管道可以支持双向通信,其中一个进程可以从管道中读取数据,而另一个进程可以向管道中写入数据。

  4. 阻塞和非阻塞:默认情况下,对有名管道的读取和写入操作是阻塞的,即如果没有数据可读或管道已满,进程将被阻塞。但是,可以通过设置文件描述符为非阻塞模式来实现非阻塞的读写操作。

  5. 管道容量有限:有名管道的容量是有限的,取决于系统的设置。如果管道已满,进程写入操作可能会被阻塞。

  6. 进程间独立:有名管道不会自动提供同步和互斥机制。进程需要自己协调读写操作,以避免数据竞争和同步问题。

由于有名管道在文件系统中具有唯一路径名,使得它们非常适合需要持久性进程间通信的应用程序,例如客户端和服务器应用程序之间的通信。

补充

1.有名管道可以使互不相关的两个进程互相通信。
2.有名管道可以通过路径名来指出,并且在文件系统中可见,但内容存放在内存中。
3.进程通过文件IO来操作有名管道
4.有名管道遵循先进先出规则,不支持lseek()操作
5.半双工通信

1.2有名管道注意事项

在使用有名管道(Named Pipes)进行进程间通信时,以下是一些需要注意的事项:

  1. 创建和删除:在使用有名管道之前,必须通过调用 mkfifo() 函数来创建管道。使用 rm 命令或 unlink() 函数来删除有名管道。确保正确处理有名管道的创建和删除,以避免潜在的资源占用和权限问题。

  2. 文件权限:有名管道在文件系统中以特殊文件的形式存在,因此需要正确设置文件权限以控制进程对管道的访问。确保正确地为有名管道设置合适的权限,以保护管道的安全和保密性。

  3. 同步和阻塞:有名管道的读取和写入操作默认是阻塞的,即进程在读取或写入时会被阻塞,直到操作完成。因此,需要注意防止进程陷入死锁和无限阻塞情况。可以使用非阻塞模式设置文件描述符,或使用多线程或多进程机制来处理并发读写操作。

  4. 缓冲区大小:有名管道的容量是有限的,取决于系统的设置。如果管道已满,写入操作可能被阻塞。因此,在实现进程间通信时,需要适当设置和管理缓冲区大小,以避免数据丢失和性能问题。

  5. 错误处理:使用有名管道时,需要适当处理错误和异常情况,并进行错误检查。例如,在打开管道文件、读写数据和处理管道关闭等情况下,需要检查系统调用或库函数的返回值,以确保操作正确完成。

  6. 进程间同步:有名管道本身不提供进程间同步和互斥机制。如果多个进程同时读取和写入管道,可能会导致数据竞争和不确定行为。因此,需要使用其他同步机制(如信号量、互斥锁等)来确保进程之间的正确协调和数据一致性。

  7. 关闭管道:及时关闭有名管道文件描述符,以及在不使用管道时适当地删除管道。这样可以释放系统资源,并避免潜在的问题和错误。

总之,在使用有名管道进行进程间通信时,需要考虑文件权限、同步和阻塞、缓冲区大小、错误处理等方面的因素,以确保通信的正确性、可靠性和安全性。

补充

1.以只写方式打开有名管道,写阻塞(open),直到另一个进程将读打开
2.以只读方式打开有名管道,读阻塞(open),直到另一个进程将写打开
3.以可读可写方式打开有名管道,管道中无数据,读阻塞,当管道中写满数据,写阻塞

1.3mkfifo函数

mkfifo() 是一个系统调用函数,用于创建有名管道(Named Pipes)。以下是该函数的原型和用法:

#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

参数说明:

  • pathname:要创建的有名管道的路径名。
  • mode:创建的有名管道的权限(权限掩码)。使用 chmod 命令中的权限表示法,如 0666

返回值:

  • 成功时,返回0。
  • 失败时,返回-1,并设置 errno 来指示具体错误。

示例用法:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

int main() {
    
    
    const char *pathname = "/tmp/my_fifo";

    int result = mkfifo(pathname, 0666);
    if (result == 0) {
    
    
        printf("有名管道创建成功\n");
    } else {
    
    
        perror("有名管道创建失败");
        exit(EXIT_FAILURE);
    }

    return 0;
}

在上述示例中,mkfifo() 函数将创建一个 /tmp/my_fifo 的有名管道。如果创建成功,将打印一条成功消息;否则,将打印错误信息。

请确保确保创建的有名管道路径名的有效性和权限设置的正确性,并根据需要进行错误检查处理。

1.4编程实战

好的,以下是一个使用有名管道进行进程间通信的简单例子:

发送消息的进程(writer.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    
    
    const char *fifoPath = "/tmp/myfifo";
    int fd;

    // 创建有名管道
    mkfifo(fifoPath, 0666);

    // 打开管道以进行写操作
    fd = open(fifoPath, O_WRONLY);

    // 发送消息到管道
    const char *message = "Hello, reader!";
    write(fd, message, strlen(message) + 1);
    close(fd);

    return 0;
}

接收消息的进程(reader.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    
    
    const char *fifoPath = "/tmp/myfifo";
    int fd;
    char buffer[256];

    // 打开管道以进行读操作
    fd = open(fifoPath, O_RDONLY);

    // 从管道读取消息
    read(fd, buffer, sizeof(buffer));
    printf("接收到的消息: %s\n", buffer);
    close(fd);

    return 0;
}

在上述例子中,发送消息的进程使用 mkfifo() 函数创建了一个有名管道,并使用 open() 函数以只写模式打开了管道。然后,使用 write() 函数将消息写入管道中。

接收消息的进程同样使用 open() 函数以只读模式打开了相同的管道,并使用 read() 函数从管道中读取消息。然后,打印出接收到的消息。

请确保在运行这两个进程之前,在命令行中先编译它们:

gcc writer.c -o writer
gcc reader.c -o reader

然后,可以分别运行 ./writer./reader 来观察进程间通过有名管道进行的简单消息通信。

猜你喜欢

转载自blog.csdn.net/m0_73731708/article/details/133100802