简单的 Linux IPC 问题
Posted
技术标签:
【中文标题】简单的 Linux IPC 问题【英文标题】:Simple Linux IPC Question 【发布时间】:2010-12-22 19:34:05 【问题描述】:目前我有一个客户端进程和一个服务器进程。客户端进程需要经常联系服务器进程以交换数据,但需要知道服务器的 pid 才能这样做。客户应该如何知道如何做到这一点?我想避免重复的硬盘访问。此应用程序仅在 linux 下运行。当前,服务器使用其 pid 或 RAM 磁盘设置一个锁定文件。客户端检查文件。我还能如何有效地完成此事务,以便服务器可以向客户端发送信号? (注:客户端是php,服务器是c)
【问题讨论】:
正如其他人所建议的那样,我错误地处理了整个问题,但是:确实存在一种方便的方法来精确地完成我当时想做的事情(优化重复的文件系统访问)!它是经常挂载在 /dev/shm 的 tmpfs 文件系统。它可能不是 100% 跨发行版的可移植性,但它似乎是相当标准的。 【参考方案1】:一些想法:
-
什么都不做;如果您反复读取它,读取磁盘文件(在正确的永久磁盘上)不会导致任何 IO,因为该文件已经在缓存中。
重构您的系统,这样您就不需要知道 pid 文件了
你确定你真的在乎吗?过早的优化等等。您每秒执行多少次,1000 次或更多?
【讨论】:
【参考方案2】:我假设,当您说“进程”时,这两个在同一台机器上?如果是这样,您可以使用/tmp
目录中的命名FIFO。这是两个进程使用 IPC 的示例,命名为 FIFO /tmp/test.fifo
和 fork()
:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/stat.h>
int errno;
int main(int argc, char** argv)
char fifo_path[] = "/tmp/test.fifo";
char buffer[128];
int result = mkfifo(fifo_path, 0600);
printf("mkfifo result = %d\n", result);
if (errno == EEXIST)
printf("errno == EEXIST\n");
pid_t child = fork();
if (child == 0)
printf("%d> child; opening fifo \"%s\" for writing\n", getpid(),
fifo_path);
FILE* fifo = fopen(fifo_path, "w");
char in_buffer[128];
fgets(in_buffer, 128, stdin);
fputs(in_buffer, fifo);
fclose(fifo);
else
printf("%d> parent; opening fifo \"%s\" for reading\n", getpid(),
fifo_path);
FILE* fifo = fopen(fifo_path, "r");
fgets(buffer, 128, fifo);
if (buffer[0] == EOF)
printf("%d> got EOF\n", getpid());
else
buffer[strlen(buffer) - 1] = 0;
printf("%d> read string \"%s\"\n", getpid(), buffer);
fclose(fifo);
return 0;
所以只要两个进程都知道 FIFO 的完整路径,就可以对其进行读写。
【讨论】:
这是我已经做的,但问题是同步。目前我的设置是让客户端信号服务器准备好进行事务处理,然后事务发生在服务器的信号处理函数中。它如何知道将信号发送到哪个 pid? 你不需要知道PID;您只需要知道客户端是否正在读取 FIFO。有一种方法可以做到这一点;不过我不确定。我相信服务器在写入 FIFO 时会阻塞,直到它被打开以供读取。您可以使用某些参数创建 FIFO,这意味着服务器不会阻塞,但如果没有被读取,服务器将收到 SIGPIPE 信号。我希望这会有所帮助。【参考方案3】:通常您不使用 pid,而是使用某种地址 - IP 地址(包括端口)、Unix 域套接字地址、文件系统中的路径或构建在一个之上的一些更高级别的 IPC 系统其中(D-Bus、X 等)到达服务器并与之通信。 pid 唯一有用的是发送信号,这可能是一种非常糟糕的通信方式,如果您将客户端和服务器分成不同的权限域,它将无法工作。
【讨论】:
好的,好的,很好,我喜欢这样的声音,而且我已经不得不做一些不愉快的事情来获得正确的权限,但是如果我实现这个我的服务器怎么知道当客户要求某事时? 它需要在大部分时间做一件事(为客户收集数据),然后当客户要求时它需要传输。现在,信号处理程序允许我在信号进入时异步执行代码。但是使用套接字......我可以为套接字设置某种事件处理程序吗?我应该分叉并让一个分支循环监听套接字吗? 对此有两种通用方法。一种是使用select
(或poll
)将您的服务器构建为一个事件循环,以等待来自多个文件描述符中的任何一个的输入,并且可能还等待从缓冲区写入输出的能力。另一种是使用线程或单独的进程,每个进程都阻塞在 IO 中。但是,如果您使用进程,您将遇到如何使它们通信并最终返回select
的问题。所以我要么只使用select
循环开始,要么使用线程(与条件变量和障碍等pthread原语通信)。【参考方案4】:
其他一些选项包括:
-
将服务器设置为侦听特定端口。
服务器可以设置命名管道,客户端可以通过它与之通信。
【讨论】:
所以...没有人回答我的问题。我的问题不完全是关于 IPC。它是关于 IPC 的同步。我已经让客户端和服务器通过命名管道进行通信。问题是服务器应该如何知道何时监听管道。现在这是通过信号完成的(因此知道服务器的 pid 并将其保存在重复访问信息不会垃圾磁盘读取的地方的问题)。您是说服务器不做任何其他事情时应该只在管道上侦听客户端通信,而不是尝试同步?【参考方案5】: Unix 域套接字 D-Bus【讨论】:
【参考方案6】:我认为您可以在非阻塞模式下使用名称 IPC 消息队列。我不知道命名管道是否支持非阻塞模式,但如果是,那么你也可以使用它。在 non_block 模式下,您只需注册队列描述符以发出信号并进入一般等待。如果队列中有任何活动,您的进程将被唤醒。请在互联网上进行一些搜索,您可以找到许多相同的示例。
要给出正确/准确的答案,我应该知道您的服务器进程设计。
【讨论】:
以上是关于简单的 Linux IPC 问题的主要内容,如果未能解决你的问题,请参考以下文章