Linux进程间通信的方式汇总

Linux进程间通信的方式汇总


Linux进程间通信的方式主要有以下几种:

  1. 管道(Pipe):管道是一种最简单的IPC方式,用于实现父子进程之间的通信。一个进程可以向管道中写入数据,另一个进程可以从管道中读取数据。
  2. 命名管道(Named Pipe)或FIFO(First In First Out):类似于管道,但是命名管道允许无亲缘关系的进程之间进行通信。它在文件系统中有对应的文件名,并通过文件描述符来访问。
  3. 信号(Signal):信号是在软件层次上对中断机制的一种模拟,用于通知进程有某事件发生。一个进程收到一个信号后,可以根据信号的不同含义来执行不同的操作。
  4. 消息队列(Message Queue):消息队列是消息的链接表,它允许进程之间通过发送和接收消息来进行通信。消息队列被内核维护,保证了消息的独立性和安全性。
  5. 共享内存(Shared Memory):共享内存允许多个进程访问同一块内存区域,进程可以直接读写该内存区域来进行通信。这种方式通信速度快,但需要同步机制来避免冲突。
  6. 信号量(Semaphore):信号量是一种用于进程间同步和互斥的机制,可以控制对共享资源的访问,避免竞争和死锁等问题。
  7. 套接字(Socket):套接字不仅可以用于本地进程间通信,还可以用于网络通信。它提供了一种跨网络平台的进程间通信机制,使得不同主机上的进程可以进行通信。

这些通信方式各有特点,可以根据具体的应用场景和需求来选择合适的通信方式。

管道

下面是一个简单的 Linux C 示例代码,它演示了如何使用管道(pipe)来实现父进程和子进程之间的通信。在这个例子中,父进程会向管道中写入一个字符串,然后子进程会从管道中读取这个字符串并打印出来。

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/types.h>  
#include <sys/wait.h>  
  
int main() {
     
    int fd[2]; // 文件描述符数组,用于管道的读写  
    pid_t pid; // 子进程的进程ID  
    char buf[1024]; // 用于存储从管道读取的数据的缓冲区  
    const char *message = "Hello from parent process!"; // 父进程要发送的消息  
  
    // 创建管道  
    if (pipe(fd) == -1) {
     
        perror("pipe");  
        exit(EXIT_FAILURE);  
    }  
  
    // 创建子进程  
    pid = fork();  
    if (pid == -1) {
     
        perror("fork");  
        exit(EXIT_FAILURE);  
    }  
  
    // 父进程  
    if (pid > 0) {
     
        close(fd[0]); // 关闭读端,因为父进程要写入  
  
        // 写入消息到管道  
        write(fd[1], message, strlen(message) + 1);  
        close(fd[1]); // 写入完毕后关闭写端  
  
        // 等待子进程结束  
        waitpid(pid, NULL, 0);  
        printf("Parent process has finished.\n");  
    }  
    // 子进程  
    else {
     
        close(fd[1]); // 关闭写端,因为子进程要读取  
  
        // 从管道读取消息  
        ssize_t bytesRead = read(fd[0], buf, sizeof(buf) - 1);  
        if (bytesRead > 0) {
     
            buf[bytesRead] = '\0'; // 在读取到的字符串末尾添加空字符  
            printf("Child process received: %s\n", buf);  
        }  
        close(fd[0]); // 读取完毕后关闭读端  
  
        exit(EXIT_SUCCESS);  
    }  
  
    return 0;  
}

在这个示例中,首先通过 pipe() 函数创建了一个管道,并返回了两个文件描述符 fd[0]fd[1],分别代表管道的读端和写端。

接着,使用 fork() 函数创建了一个子进程。在父进程中,关闭了管道的读端,并使用 write() 函数将消息写入管道的写端。写入完成后,关闭了写端,并等待子进程结束。

在子进程中,关闭了管道的写端,并使用 read() 函数从管道的读端读取消息。读取到的消息存储在 buf 缓冲区中,并打印出来。读取完成后,关闭了读端,并退出子进程。

注意,在实际使用中,通常需要对 read()write() 函数的返回值进行检查,以处理可能出现的错误情况。在这个简单的示例中,为了简洁,我省略了错误检查代码。在实际编程中,请确保添加适当的错误处理逻辑。

命名管道

下面是一个简单的 Linux C 示例代码,它演示了如何使用命名管道(named pipe)来实现进程间的通信。在这个例子中,我们将创建一个命名管道,一个进程写入数据,另一个进程读取数据。

首先是写入数据的进程(writer.c):

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <sys/stat.h>  
#include <sys/types.h>  
#include <unistd.h>  
  
#define FIFO_PATH "/tmp/my_named_pipe"  
#define BUFFER_SIZE 256  
  
int main() {
     
    int fd;  
    char buffer[BUFFER_SIZE];  
    const char *message = "Hello from named pipe writer!";  
  
    // 创建命名管道  
    if (mkfifo(FIFO_PATH, 0666) == -1) {
     
        perror("mkfifo");  
        exit(EXIT_FAILURE);  
    }  
  
    // 打开命名管道以写入数据  
    fd = open(FIFO_PATH, O_WRONLY);  
    if (fd == -1) {
     
        perror("open");  
        exit(EXIT_FAILURE);  
    }  
  
    // 写入数据到命名管道  
    if (write(fd, message, strlen(message) + 1) == -1) {
     
        perror("write");  
        exit(EXIT_FAILURE);  
    }  
  
    close(fd);  
    printf("Writer process has finished writing.\n");  
  
    // 删除命名管道  
    unlink(FIFO_PATH);  
  
    return 0;  
}

然后是读取数据的进程(reader.c):

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <unistd.h>  
  
#define FIFO_PATH "/tmp/my_named_pipe"  
#define BUFFER_SIZE 256  
  
int main() {
     
    int fd;  
    char buffer[BUFFER_SIZE];  
  
    // 打开命名管道以读取数据  
    fd = open(FIFO_PATH, O_RDONLY);  
    if (fd == -1) {
     
        perror("open");  
        exit(EXIT_FAILURE);  
    }  
  
    // 从命名管道读取数据  
    ssize_t bytesRead = read(fd, buffer, BUFFER_SIZE - 1);  
    if (bytesRead == -1) {
     
        perror("read");  
        exit(EXIT_FAILURE);  
    }  
  
    buffer[bytesRead] = '\0'; // 添加字符串结束符  
    printf("Reader process received: %s\n", buffer);  
  
    close(fd);  
  
    return 0;  
}

要运行这两个程序,你需要分别编译它们:

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

然后,你可以先运行 reader 进程来等待命名管道的打开:

./reader

在另一个终端窗口中,运行 writer 进程来写入数据:

./writer

如果一切正常,你应该在第一个终端窗口中看到 reader 进程打印出从 writer 进程接收到的消息。

注意,命名管道(FIFO)在文件系统中有一个路径,所以你需要确保该路径是存在的并且有足够的权限进行读写操作。此外,你还需要处理可能发生的错误情况,比如命名管道不存在或打开失败等。在这个简单的示例中,为了保持代码的简洁性,我省略了这些错误处理逻辑。在实际编程中,请确保添加适当的错误处理代码。

信号

下面是一个简单的 Linux C 示例代码,它演示了如何使用信号(Signal)来在进程之间发送通知。在这个例子中,我们将创建一个进程,它将发送一个 SIGUSR1 信号给自身,并在接收到信号时执行一个特定的处理函数。

#include <stdio.h>  
#include <stdlib.h>  
#include <signal.h>  
#include <unistd.h>  
  
// 信号处理函数  
void signal_handler(int signo) {
     
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值