在C语言中向另一个程序的标准输入写入数据/从另一个程序的标准输出读取数据

4
这是一个作业问题。我有三个程序A、B和C,它们不是父/子进程,而是独立的程序。B必须向A的标准输入写入一条消息("Hello"),并从C的标准输出读取另一条消息("Hello")。我应该使用哪个概念来实现它?我找了一段时间,但没有找到合适的东西。我想我应该使用FIFO,但我无法重定向管道。我能用FIFO和dup2吗?如果可以,怎么做?这不是作业本身,只是它应该工作的方式。然后我会在它上面实现其他东西。(如果需要,我可以发布我的基于FIFO的代码,但现在不要这样做,因为我不确定。)

您可以使用管道(参见pipe(2)和popen(3))来获取连接的文件描述符(一个的标准输入连接到另一个的标准输出)。 - Ahmed Masud
@Drew McGowen,因为是这样要求的。 - user3717434
@AhmedMasud 哎呀,我看错问题了。我的错。 - Drew McGowen
管道始终用于父子进程之间的通信。Shell 的作用是启动一个管道,然后进行两个 fork() 操作,并在每个 fork 中执行两个子进程。 - Ahmed Masud
@twalberg,OP简单地说“程序B向程序A的stdin写入数据,并从程序C的stdout读取数据”。我猜想使用FIFO,但结果并不如预期。我实际上是在问应该使用哪个概念(尽可能使用标准posix),以及如何使用。 - user3717434
显示剩余3条评论
2个回答

4

如果我误解了问题,请让我知道。

假设您创建了程序 ABC。在编程方面,您可以使用man 1 mkfifoman 3 mkfifo来创建命名管道。

然后,每个进程都会打开(2)它们,并根据它们的需求使用dup2(2)

例如,程序 A 可以像这样重定向其 stdout

int fifo = open("fifo_1", O_WRONLY);
dup2(fifo, 1);

或者程序 B 可以通过以下方式同时重定向其 stdinstdout

int fifo_in = open("fifo_1", O_RDONLY);
int fifo_out = open("fifo_2", O_WRONLY);

dup2(fifo_in, 0);
dup2(fifo_out, 1);

或者任何其他您需要的东西。


请查看我发布的答案。有示例代码。非常感谢。 - user3717434

1
我按照@chrk的解释修改了这段代码。它是来自书籍“高级Unix编程”的先进Unix编程(FIFO)示例,一个简单的服务器客户端示例。客户端将三个小写字符串发送到服务器,服务器将它们变成大写字母并通过FIFO(“fifo#clientpid”是客户端FIFO的名称)发送回客户端。客户端将它们打印到其stdout上。所以我修改了它,以便在从客户端接收消息后,服务器将大写字母字符串写入客户端的STDINT。而客户端则从STDINT读取它们并打印到其stdout上。它按照我的期望工作。感谢所有帮助。起初我实现得有些错误,但在chrk的帮助下,我又重新写了一遍。下面是代码:
客户端的输出
client 2941 started
client 2941: applesauce --> APPLESAUCE
client 2941: tiger --> TIGER
client 2941: mountain --> MOUNTAIN
Client 2941 done

服务器:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>

#define ec_neg1(s,m) if((s) == -1) {perror(m); exit(errno);}

#define SERVER_FIFO_NAME "fifo_server"
#define PERM_FILE        0664

struct simple_message {
pid_t sm_clientpid;
char sm_data[200];
};


int main()
{
  int fd_server, fd_client, i;
  ssize_t nread;
  struct simple_message msg;
  char fifo_name[100];
  printf("server started\n");

  if (mkfifo(SERVER_FIFO_NAME, PERM_FILE) == -1 && errno != EEXIST)
  {perror("can't make fifo"); exit(errno); }

  ec_neg1( fd_server = open(SERVER_FIFO_NAME, O_RDWR), "cant open fd_server" )

  while (1) 
  {
     ec_neg1( nread = read(fd_server, &msg, sizeof(msg)), "can't read from fd_server")

     if (nread == 0) {
       errno = ENETDOWN;
       perror("nread == 0"); exit(errno);
      }

     for (i = 0; msg.sm_data[i] != '\0'; i++)
       msg.sm_data[i] = toupper(msg.sm_data[i]);

     make_fifo_name(msg.sm_clientpid, fifo_name, sizeof(fifo_name));

     ec_neg1( fd_client = open(fifo_name, O_WRONLY), "can't open fifo_name" )

     ec_neg1( write(fd_client, &msg, sizeof(msg)), "can't write to fd_client" )

     ec_neg1( close(fd_client), "can't close fd_client" )
   }

/* never actually get here */
 ec_neg1( close(fd_server), "can't close fd_server" )
 exit(EXIT_SUCCESS);

 return 0;

 }


int make_fifo_name(pid_t pid, char *name, size_t name_max)
{
 snprintf(name, name_max, "fifo%ld", (long)pid);
 return 0;
}

客户端。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#define ec_neg1(s,m) if((s) == -1) {perror(m); exit(errno);}

#define SERVER_FIFO_NAME "fifo_server"
#define PERM_FILE        0664

struct simple_message {
pid_t sm_clientpid;
char sm_data[200];
};


int make_fifo_name(pid_t pid, char *name, size_t name_max)
{
 snprintf(name, name_max, "fifo%ld", (long)pid);
 return 0;
}

int main()
{
 int fd_server, fd_client = -1, i;
 ssize_t nread;
 struct simple_message msg;
 char fifo_name[100];
 char *work[] = {
   "applesauce",
   "tiger",
   "mountain",
   NULL
 };

 printf("client %ld started\n", (long)getpid());

 msg.sm_clientpid = getpid();

 make_fifo_name(msg.sm_clientpid, fifo_name,
       sizeof(fifo_name));

 if (mkfifo(fifo_name, PERM_FILE) == -1 && errno != EEXIST)
   {perror("can't make fifo"); exit(errno); }

 ec_neg1( fd_server = open(SERVER_FIFO_NAME, O_WRONLY), "can't open fd_server" )

 for (i = 0; work[i] != NULL; i++) 
 {
   strcpy(msg.sm_data, work[i]);

   ec_neg1( write(fd_server, &msg, sizeof(msg)),"can't write to fd_server" )

   if (fd_client == -1){
     ec_neg1( fd_client = open(fifo_name, O_RDWR), "can't open fifo_name"  )
     ec_neg1(dup2(fd_client, 0), "can't duplicate stdin")
   }
     ec_neg1( nread = read(0, &msg, sizeof(msg)), "can't read from fd_client" )
   if (nread == 0) {
       errno = ENETDOWN;
       perror("nread == 0"); exit(errno);
   }
   printf("client %ld: %s --> %s\n", (long)getpid(),
             work[i], msg.sm_data);
 }

 ec_neg1( close(fd_server), "can't close fd_server" )
 ec_neg1( close(fd_client), "can't close fd_client" )
 ec_neg1( unlink(fifo_name), "can't unlink fifo_name" )

 printf("Client %ld done\n", (long)getpid());
 exit(EXIT_SUCCESS);

}

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