117.info
人生若只如初见

Linux C++中如何进行进程间通信

在Linux环境下,C++程序可以使用多种方法进行进程间通信(IPC)。以下是一些常用的IPC机制:

  1. 管道(Pipes):

    • 匿名管道(Anonymous Pipes):通常用于父子进程之间的通信。
    • 命名管道(Named Pipes,FIFOs):允许无亲缘关系的进程之间进行通信。
  2. 信号(Signals):

    • 用于通知接收进程某个事件已经发生。
  3. 消息队列(Message Queues):

    • 允许进程发送和接收消息。
  4. 共享内存(Shared Memory):

    • 允许多个进程访问同一块内存区域。
  5. 信号量(Semaphores):

    • 用于进程同步,控制多个进程对共享资源的访问。
  6. 套接字(Sockets):

    • 可以用于本地进程间通信(如Unix Domain Sockets)或网络通信。

下面是一些简单的示例代码,展示了如何在C++中使用这些IPC机制:

匿名管道

#include 
#include 

int main() {
    int pipefd[2];
    char buffer[10];

    // 创建匿名管道
    if (pipe(pipefd) == -1) {
        perror("pipe");
        return EXIT_FAILURE;
    }

    // 父进程关闭写端,子进程关闭读端
    if (fork() == 0) {
        close(pipefd[1]); // 子进程关闭写端
        read(pipefd[0], buffer, sizeof(buffer)); // 读取数据
        std::cout << "Child received: " << buffer << std::endl;
        close(pipefd[0]);
    } else {
        close(pipefd[0]); // 父进程关闭读端
        write(pipefd[1], "Hello from parent", 20); // 写入数据
        close(pipefd[1]);
    }

    return EXIT_SUCCESS;
}

命名管道(FIFO)

#include 
#include 
#include 
#include 

int main() {
    const char* fifo = "/tmp/myfifo";
    mkfifo(fifo, 0666);

    int fd = open(fifo, O_RDWR);
    if (fd == -1) {
        perror("open");
        return EXIT_FAILURE;
    }

    write(fd, "Hello FIFO", 11);
    char buffer[12];
    read(fd, buffer, sizeof(buffer));
    std::cout << "Read from FIFO: " << buffer << std::endl;

    close(fd);
    unlink(fifo); // 删除FIFO

    return EXIT_SUCCESS;
}

共享内存

#include 
#include 
#include 
#include 

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666|IPC_CREAT);
    char *str = (char*) shmat(shmid, (void*)0, 0);

    strcpy(str, "Hello World");
    std::cout << "String in shared memory: " << str << std::endl;

    shmdt(str);
    shmctl(shmid, IPC_RMID, NULL);

    return EXIT_SUCCESS;
}

信号量

#include 
#include 
#include 

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int main() {
    key_t key = ftok("semfile", 65);
    int semid = semget(key, 1, 0666|IPC_CREAT);

    union semun arg;
    arg.val = 1; // 初始化信号量为1
    semctl(semid, 0, SETVAL, arg);

    // 使用semop进行P操作(等待信号量)
    struct sembuf sb = {0, -1, SEM_UNDO};
    semop(semid, &sb, 1);

    std::cout << "Semaphore value decreased to 0" << std::endl;

    // 使用semop进行V操作(释放信号量)
    sb.sem_op = 1;
    semop(semid, &sb, 1);

    semctl(semid, 0, IPC_RMID, arg);

    return EXIT_SUCCESS;
}

套接字(Unix Domain Sockets)

// 服务器端
#include 
#include 
#include 
#include 

int main() {
    int server_fd, new_socket;
    struct sockaddr_un address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    if ((server_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    address.sun_family = AF_UNIX;
    strncpy(address.sun_path, "/tmp/uds.sock", sizeof(address.sun_path)-1);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    read(new_socket, buffer, 1024);
    std::cout << "Message from client: " << buffer << std::endl;

    close(new_socket);
    close(server_fd);

    return EXIT_SUCCESS;
}

// 客户端
#include 
#include 
#include 
#include 

int main() {
    struct sockaddr_un serv_addr;
    int sock = 0;
    char *hello = "Hello from client";
    char buffer[1024] = {0};

    if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        std::cout << "\n Socket creation error \n";
        return -1;
    }

    serv_addr.sun_family = AF_UNIX;
    strncpy(serv_addr.sun_path, "/tmp/uds.sock", sizeof(serv_addr.sun_path)-1);

    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        std::cout << "\nConnection Failed \n";
        return -1;
    }

    send(sock, hello, strlen(hello), 0);
    std::cout << "Hello message sent\n";
    read(sock, buffer, 1024);
    std::cout << "Message from server: " << buffer << std::endl;

    close(sock);

    return 0;
}

在使用这些IPC机制时,需要注意同步问题,特别是在共享内存和信号量的使用中。此外,错误处理在实际应用中也非常重要。以上代码仅为示例,实际使用时需要根据具体情况进行调整。

未经允许不得转载 » 本文链接:https://www.117.info/ask/feacaAzsNAgBTDFQ.html

推荐文章

  • 如何设置Node.js日志轮转

    在Node.js中,可以使用第三方库winston和winston-daily-rotate-file来实现日志轮转。以下是设置日志轮转的步骤: 首先,确保已经安装了Node.js。如果没有,请访问...

  • Linux文件管理:怎样监控文件变化

    在Linux系统中,有多种方法可以监控文件变化。以下是一些常用的工具和方法:
    1. inotify
    inotify 是Linux内核提供的一种文件系统事件监控机制。你可以...

  • Linux下C++并发编程难点在哪

    在Linux下进行C++并发编程时,可能会遇到以下难点: 线程同步:在多线程环境下,确保数据的一致性和完整性是一个挑战。需要使用互斥锁(mutex)、条件变量(cond...

  • Linux mount命令挂载磁盘分区的注意事项

    在使用Linux的mount命令挂载磁盘分区时,有几个重要的注意事项需要遵循: 权限:挂载操作通常需要root权限。如果你不是root用户,你可能需要使用sudo来执行挂载命...

  • Golang在CentOS上如何进行日志管理

    在CentOS上使用Golang进行日志管理,你可以遵循以下步骤和策略:
    日志系统设计 日志级别:支持DEBUG、INFO、WARN、ERROR等,并支持自定义级别如TRACE。

  • Ubuntu Swagger如何进行日志管理

    在Ubuntu系统中,Swagger的日志管理可以通过配置日志系统来实现。虽然Swagger本身没有专门的日志管理功能,但你可以使用Ubuntu的日志管理工具(如rsyslog和logro...

  • Debian如何优化Kafka存储

    在Debian上优化Kafka存储主要涉及到对Kafka的配置进行调整,以及选择合适的硬件和存储解决方案。以下是一些关键的优化策略:
    存储结构优化 日志段管理:Kaf...

  • Linux进程性能瓶颈怎么破

    在Linux系统中,遇到进程性能瓶颈时,可以采取以下方法进行排查和解决: 使用top命令: top命令可以实时显示系统进程的信息,包括CPU、内存等资源的使用情况。