使用管道在进程之间发送字符串

Posted

技术标签:

【中文标题】使用管道在进程之间发送字符串【英文标题】:Using pipes to send strings between processes 【发布时间】:2016-06-21 21:25:21 【问题描述】:

我正在尝试将我的代码从 C# 重写为 C 并且遇到了一些麻烦。

所以我有一个名为 test 的文件,其中有一行文本。我想阅读该行,通过进程之间的管道将其发送并在屏幕上打印。

代码如下:

    #include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>


void
read_from_pipe (int file)

  FILE *stream;
  int c;
  stream = fdopen (file, "r");
  while ((c = fgetc (stream)) != EOF)
    putchar (c);
  fclose (stream);


void
write_to_pipe (int file)

  FILE *stream;
  FILE *testfile;
  stream = fdopen (file, "w");
  testfile = fopen("test.txt", "r");
  char *line = NULL;
  size_t len = 0;
  //ssize_t read;
  getline(&line, &len, testfile);
  fprintf (stream, "%s", line);
  free(line);
  fclose(testfile);
  fclose (stream);


int
main (void)

  pid_t pid;
  int mypipe[2];


  if (pipe (mypipe))
    
      fprintf (stderr, "Pipe failed.\n");
      return EXIT_FAILURE;
    
  pid = fork ();
  if (pid == (pid_t) 0)
    
      close (mypipe[1]);
      read_from_pipe (mypipe[0]);
      return EXIT_SUCCESS;
    
  else if (pid < (pid_t) 0)
    
      fprintf (stderr, "Fork failed.\n");
      return EXIT_FAILURE;
    
  else
    
      close (mypipe[0]);
      write_to_pipe (mypipe[1]);
      return EXIT_SUCCESS;
    

但是,在运行此代码时,我似乎遇到了分段错误。有什么我遗漏的吗?

【问题讨论】:

哪一行出现分段错误? 您应该检查来自getline() 的错误。如果出现错误,可能是没有分配line,所以你在打印的时候会出现分段错误。 getline() 调用看起来没问题。确保fopen() 成功。 当您调用getline() 时,testfile 的值是多少。 该文件可能不在您的当前目录中。尝试使用绝对路径。 【参考方案1】:

创建test.txt 文件后,它可能会正常工作。 至少在我的机器上修复了它。

在 C 语言中,您通常需要进行一些相当繁琐的错误检查才能稳健地编写程序。例如,您应该编写如下内容:

int read_from_pipe (int file) 
  FILE *stream;
  int c;
  if((stream = fdopen (file, "r"))==NULL) goto err;

  while ((c = fgetc (stream)) != EOF)
    putchar (c);
  
  if(ferror(stream)) int er=errno; fclose (stream); errno=er; goto err; 
  return 0;
err:
  perror("read"); return -errno; 

等等

测试文件的fopen 行看起来像:

if(!(testfile = fopen("test.txt", "r")))  perror("write"); return -errno; 

您可能收到了很好的"write: No such file or directory" 消息。

【讨论】:

if(ferror(stream)) fclose( stream ); goto err; 有问题。 fclose 可能会失败,修改errno。在这种情况下,错误处理中打印的错误消息将具有误导性。所以……需要更多的乏味。 @WilliamPursell 谢谢【参考方案2】:

您的程序崩溃的可能性有多种,但很可能是因为您缺少一些重要的检查,并且您的程序的工作目录中缺少文件“test.txt”。

缺少的第一个检查是 testfile 是否为 NULL:

testfile = fopen("test.txt", "r");

testfile 文件指针未经检查地传递给 getline(),如果传递一个无效的文件指针,可能会使程序崩溃。 正如 Barmar 之前所说,即使 testfile 有效, getline() 本身也可能会失败,但是在我当前的 Debian 上,手册页没有说明在错误条件下行指针会发生什么,所以我只检查返回值

最后一点,如果你正在学习这类东西,你应该学习如何使用 gdb。 像这样使用:

$ gcc -ggdb3 -o pipetest pipetest.c
$ gdb pipetest 
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
[...]
(gdb) run
Starting program: /home/thilo/code/test/pipetest 

Program received signal SIGSEGV, Segmentation fault.
_IO_getdelim (lineptr=0x7fffffffe068, n=0x7fffffffe060, delimiter=10, fp=0x0) at iogetdelim.c:56
56      iogetdelim.c: No such file or directory.
(gdb) bt
#0  _IO_getdelim (lineptr=0x7fffffffe068, n=0x7fffffffe060, delimiter=10, fp=0x0) at iogetdelim.c:56
#1  0x00000000004008fb in write_to_pipe (file=4) at pipetest.c:28
#2  0x00000000004009d9 in main () at pipetest.c:62
(gdb) frame 1
#1  0x00000000004008fb in write_to_pipe (file=4) at pipetest.c:28
28        getline(&line, &len, testfile);
(gdb) print line
$1 = 0x0

【讨论】:

【参考方案3】:

此代码在我的机器(Linux 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u2 x86_64 GNU/Linux)上正常运行,无需修改。 我删除了“test.txt”文件,结果出现了分段错误。

因此,我认为您遇到的问题是“test.txt”文件不存在,或者您没有运行程序的用户的读取权限。

【讨论】:

以上是关于使用管道在进程之间发送字符串的主要内容,如果未能解决你的问题,请参考以下文章

管道,进程间数据共享,进程池

尝试通过运行 Tkinter 的发送进程在进程之间通过管道发送任何内容时出现管道损坏错误

如何使用管道在两个程序之间发送一个简单的字符串?

在 C 中使用管道运行并发进程

为啥在并行子进程之间分叉两次后 pipe() 不工作?

linux进程通信