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

时间:2011-02-02 10:33:22

标签: c linux posix fork

我需要创建一个可以进行无线网络扫描的linux应用程序,将结果放入一个结构中并以某种方式将其发送到另一个将使用该数据的主应用程序。 我最初的想法是在主应用程序中创建一个管道,fork并通过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 个答案:

答案 0 :(得分:7)

我怀疑发生了什么fgets()正在正确地读取NUL字符,但是你将第一个解释为读取的行的结尾。这很棘手,因为fgets()用于文本输入,它确实使用'\ 0'作为标记,而不是返回读取的字符数。即使您知道每一行都将\n终止,也可以将一行中嵌入的原始二进制数据包含\n。所以,切换到fread(),这是二进制文件。您可以在每条消息的前面放置一个固定长度(例如2字节,4字节)的消息大小,以便另一方可以先读取该消息,然后针对确切的消息大小执行fread(),避免出现混乱问题部分消息读取。

如果确实希望保留一些奇怪的文本和二进制混合,您可以尝试在ftell()之后使用fgets()来了解您在流中的进一步是的,因此你的缓冲区中应该有多少个字符,但我从来没有见过一个严肃的系统做了那么多hacky。

对于记录而言,如果没有对二进制数据中的每个字符进行十六进制编码等非常低效的操作,您只需编码麻烦的字符即可。例如,可以使用C字符串文字转义序列,其中\0表示NUL,\\表示单个\。虽然不太容易进行视觉检查,但使用say octal \NNN编程/解码不可打印的字符可能更容易。如果有很多不可打印的字符,那么base-64 uuencode方法 - 例如在MIME电子邮件附件中使用 - 是另一种合适但完全不可读的编码。

答案 1 :(得分:3)

有很多......

我会读史蒂文斯。

http://www.kohala.com/start/unpv22e/unpv22e.html

答案 2 :(得分:2)

通常会使用freadfwrite来跨进程交换二进制结构。它适用于固定长度的记录,并且发送空值等没有问题。

我发现在我的漫长职业生涯中,在大多数应用程序中,交换ascii字符串,易于解析(例如通过scanf)而不是二进制数据要好得多。这样就可以观察和记录消息,并且可以通过远程登录和键入(通常粘贴)来测试各个进程。如果程序员只能读取消息流量,那么它就更容易开发。

答案 3 :(得分:0)

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

看看,作为奖励,您的流程甚至可以在远程计算机上进行通话。

欢迎来到云端。