在Linux中如何在进程间交换二进制数据

6

我需要创建一个Linux应用程序,它可以进行无线网络扫描,将结果放入结构体中,并以某种方式发送给另一个主要应用程序,该应用程序将使用数据。 我的初始想法是在主要应用程序中创建一个管道,通过execl分叉并启动另一个进程,该进程可以写入管道。类似于这样:

pid_t pid = NULL;
int pipefd[2];
FILE* output;
char line[256];

pipe(pipefd);
pid = fork();
if (pid == 0)
{
// Child
  close(pipefd[0]);
  dup2(pipefd[1], STDOUT_FILENO);
  dup2(pipefd[1], STDERR_FILENO);
  execl("/sbin/wifiscan", "/sbin/wifiscan", (char*) NULL);
}

//Only parent gets here. Listen to what the wifi scan says
close(pipefd[1]);
output = fdopen(pipefd[0], "r");

while(fgets(line, sizeof(line), output))
{
//Here we can listen to what wifiscan sends to its standard output
}

然而,如果二进制0出现在输出中,则此方法无法处理二进制数据。因此,我可以将wifiscan应用程序的输出格式化为文本,将其发送到管道中并在主应用程序中解析,或者以我目前不知道的更智能的方式完成。

在Linux中,有哪些其他可靠交换进程数据的方式?

4个回答

7
我怀疑发生的情况是fgets()正确读取了NUL字符,但你将第一个字符解释为所读行的结尾。这很棘手,因为fgets()用于文本输入,并使用'\0'作为标记,而不返回已读取字符数。即使你知道每行都以\n结尾,嵌入在行中的原始二进制数据也可能包含\n。因此,请改用fread(),该函数适用于二进制数据。你可以在每个消息前加上固定长度(例如2字节、4字节)的消息大小,以便另一端先读取该大小,然后对确切的消息大小进行fread(),避免了部分消息读取的麻烦问题。
如果你真的想保持某种奇怪的文本和二进制混合方式,可以尝试在fgets()之后使用ftell()来查找流的位置,从而确定缓冲区应有多少字符,但我从未见过认真的系统这样做。
记录一下,如果不像十六进制编码二进制数据中的每个字符那样效率极低,你可以编码有问题的字符。例如,可以使用C字符串文字转义序列,其中\0表示NUL,\\表示单个\。虽然不太容易进行视觉检查,但使用八进制\NNN编码/解码非打印字符可能更容易编程。如果有很多非打印字符,则可以使用base-64 uuencode方法(例如MIME电子邮件附件中使用的方法)进行适当但完全无法读取的编码。

1
ftell() 在像管道这样的不可寻址流上可能无法正常工作。 - caf
我同意构建数据的基本协议,然后使用fread()而不是fgets()。这个答案针对FIFOs实现的问题可能会有额外的用处,因为它提供了一些关于如何构建这样一个协议的例子。 - jschmier

3

2

通常情况下,我们会使用freadfwrite来在进程之间交换二进制结构。对于固定长度的记录,它的效果非常好,发送空值等也没有问题。

在我的职业生涯中,我发现在大多数应用程序中,与其交换二进制数据,不如交换易于解析的ascii字符串(例如通过scanf解析)。这样消息就可以被观察和记录,而且可以通过telnet测试各个进程,并在它们上面输入(通常是粘贴)信息。如果程序员能够直接阅读消息流量,开发工作就会变得更加容易。


0

可靠地交换数据?这让我想起了0MQ(ZeroMQ)库:http://zeromq.org

去看看吧,作为奖励,您的进程甚至可以在远程计算机上通信。

欢迎来到云端。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接