c - Linux 中 C 中双向 IPC 的最佳方式

标签 c linux

当被问及 this question 时,我无法完成示例.
我在 Google 中搜索了实现 IPC 的方法。
我无法决定哪种方式最适合编写我的程序。
我尝试了很多实现方式,但遇到了很多麻烦。

我想要:
1. 父进程管理子进程 - OK ( template )
2. parent 和 children 必须实现新消息信号的回调
3. 一个进程不知道来自其他进程的消息大小 ( char * )

我的代码:

标题.h:

#ifndef MESSAGES_H
#define MESSAGES_H

#include <stdio.h>
#include <stdlib.h>

// need here: some includes and definitions

inline char * read_message( /* need here: some params */ ) {
    // need here: read message function
}

inline char * send_message( /* need here: some params */ ) {
    // need here: send message function
}
#endif

父类.c:

#include "header.h"

// parent specyfic includes and definitions

void on_message( /* need here: some parameters */ ) {
    char *message = read_message( /* need here: some other parameters */ );
    // do something with / if message etc.
}

int runChild(key) {
    int pid = fork();
    if (pid == 0) {
        execl("./child", "./child", /* params here */, null);
    }else{
        return pid;
    }
}

int main(int argc, char *argv[]) {
    // need here: prepare IPC
    // need here: on new message event call function "on_message"
    int childPid = runChild(key);
    // loop - for example: gtk_main()
    // need here: close childs
}

child .c

#include "header.h"

// child specyfic includes and definitions

void on_message( /* need here: some parameters */ ) {
    char *message = read_message( /* need here: some other parameters */ );
    // do something with / if message etc.
}

int main(int argc, char *argv[]) {
    // need here: prepare IPC
    // need here: on new message event call function "on_message"
    int pid = getpid();
    int parentPid = getppid();
    printf("Child with pid %d is ready for messages from parent with pid: %d", pid, parentPid);
    // event loop - for example: gtk_main()
}

在该示例程序模板中哪种 IPC 方式更好(安全且速度快)? 您能否分享一个与上述模板匹配的非常简单的示例?

最佳答案

有许多不同的方法可以实现 IPC。为了更好地比较,请参阅 Stevens'图书。经典的是《UNIX 环境高级编程》,但也有《UNIX 网络编程,第2 卷,第二版:进程间通信》。我知道有时指向别处的引用并不被认为是好的形式,但无论这是学术问题还是商业问题,大多数 UNIX 程序员都会将史蒂文斯视为宝贵的资源。

也就是说,这是 IPC 的主要选项:

  1. 在进程之间使用 pipe()。格式将始终基于流;如果您要发送数据结构,这可能会很痛苦,因为您不仅需要担心序列化,还需要担心缓冲并将“数据包”转换回消息。管道是单向的,因此您需要两个管道进行双向通信。

  2. 使用命名管道或 fifo。这允许多对一通信,并且 fifo 在一端退出后仍然存在。否则按照 (1)。

  3. 在进程之间使用 socketpair - 特别是 unix 域套接字。套接字是双向的。您可以使用流式套接字 (SOL_STREAM)、数据报(不可靠,无法保证顺序 - SOCK_DGRAM)或者更好的顺序可靠双向数据包通信(SOCK_SEQPACKET).基于数据包的通信意味着您可以(例如)在每个数据包中放置一个数据结构。

  4. 使用信号。实际上,您可以一次发送一个整数。信号不能很好地与线程混合,处理中断的系统调用很困难,并且各种竞争条件使它们不可靠,除非您知道自己在做什么并且不太担心可移植性。大多数情况下最好避免。

  5. 使用系统 V 信号量(semget 等)或 POSIX 信号量(sem_open 等)。对于在进程之间发送信号以实现同步很有用,但仅此而已。

  6. 使用共享内存(shmget 等)- 相同的页面对多个进程可见。您将需要结合一些同步方法。

  7. System V 消息队列(msgget 等)- 维护两个进程之间的数据包(消息)队列。

  8. 上述的一些组合。

我只在内核的分支(例如 Binder)或开发中(例如 KDBus)省略了一些东西。

可以找到几乎所有上述内容的示例和教程 here .

现在,其中大部分都可以用于您提到的应用程序。看起来你想发送可变大小的消息,所以如果你使用基于流的协议(protocol),正常的 hack 是发送数据包的长度作为前 1、2 或 4 个字节(取决于最大长度)。基于数据包的协议(protocol)在这里(显然)更容易,但每个协议(protocol)都有自己的最大数据包大小。你关心可靠性吗?你关心便携性吗?你关心速度吗?在它们之间进行选择时,所有这些都是合理的考虑因素。

最后,基于 FD 的方法(例如管道、套接字对)的一个优点是您可以将它们添加到普通的 select() 循环中;如果您的程序中还有其他事情正在进行,这可能会有所帮助。

您在评论中询问了一些 socketpair 代码示例。我重申顶部关于 Stephens 的评论。如果没有:

  • Socketpair() in C/Unix显示了使用 fork() 为 IPC 设置套接字对的一个很好的示例。
  • 上面提到的教程有一个很好的部分是关于socketpair() here .

关于c - Linux 中 C 中双向 IPC 的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27368952/

相关文章:

c - 如何在 GtkOptionMenu/GtkComboBox 中禁用鼠标滚轮滚动

c - 是否可以定义一个 "(' 被转义的宏?

python - 在 Python 中检索从 .so 导出的 C 函数返回的 `char *`

linux - SVN新存储库永久移动

php - 开箱即用的 php 目录结构组件

c - mmap 需要 shm_open 吗?

c - 用C语言解析单词;翻译程序

linux - glibc-2.24 无法在 LFS 系统上编译,日志显示 -V 参数未被识别,但我没有传递 -V

R 错误 : dependencies ‘xml2’ , ‘httr’ 不适用于软件包 (Linux Mint 20.1)

linux - Linux 中读取文件