无法从 C 中的管道读取数据?
Cannot perform reading from pipe in C?
我正在编写代码来与涉及读取和写入应用程序的应用程序进行交互。这是代码:第一个 - 即 input.c 与第二个交互 - 即 app.c
//input.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#define WRITE 1
#define READ 0
void error(char* msg){
perror(msg);
exit(-1);
}
void got_here(char* msg){
printf("Got_here:%s\n",msg);
}
int main(int argc, char** argv, char** envp){
int fd_parent[2];
int fd_child[2]; // for parent and child to write respectively
if(pipe(fd_parent) < 0 | pipe(fd_child) < 0){
error("Fail to create a pipe"); /// just an error-handle function
}
pid_t child = fork();
if(child < 0){
error("Fail to create a child");
}
else if(child == 0){
dup2(fd_child[WRITE], STDOUT_FILENO);
dup2(fd_parent[READ], STDIN_FILENO);
close(fd_parent[WRITE]);
close(fd_child[READ]);
char str[100] = "./app";
execve(str, argv,envp);
close(fd_parent[READ]);
close(fd_child[WRITE]);
return 0;
}
else{
close(fd_parent[READ]);
close(fd_child[WRITE]);
FILE* stream = fdopen(fd_child[READ], "r");
FILE* stream_write = fdopen(fd_parent[WRITE], "w");
char str[20];
char menu[4] = "10\n";
fread(str,sizeof(char), 20, stream); // Here is where the problem lies
got_here("after read"); // it does not get here
fwrite(menu, sizeof(char), 3, stream_write);
fflush(stream_write);
fclose(stream);
fclose(stream_write);
printf("Parent Done\n");
return 0;
}
}
这是应用程序代码(为了缩短代码,我只包括主要内容):
int main(int argc, char** argv, char** envp){
char str[10];
printf("- Select Menu -1\n");
printf("1. Play Lotto\n");
scanf("%s", str);
return 0;
}
在 运行 之后,我的程序只是暂停在 fread()
行,它应该完成对应用程序的读取和写入。有趣的是,如果我在第二个程序中省略 scanf()
或 printf()
,它就可以正常工作。我尝试更改 fwrite
和 fread
的位置,但问题仍然存在。我认为这是与缓冲区相关的问题,但我尝试与之交互的应用程序不允许更改,因此我不能包含 fflush
或其他内容。
我的猜测是对的还是另有解释?以及如何克服这个问题?
您可以使用stdbuf命令修改管道另一端程序的缓冲选项。为了在 C 中执行此操作,您可以编写:
char str[100] = "./app";
char **new_argv = malloc (sizeof (char *) * (argc + 9));
new_argv[0] = "stdbuf";
new_argv[1] = "-i";
new_argv[2] = "0";
new_argv[3] = "-o";
new_argv[4] = "L";
new_argv[5] = "-e";
new_argv[6] = "L";
new_argv[7] = str;
memcpy (&new_argv[8], &argv[1], argc - 1);
new_argv[argc + 8] = NULL;
execvp ("stdbuf", new_argv);
error ("execvp");
或者如果您真的不需要将父项的参数传递给子项,则:
execlp ("stdbuf", "stdbuf", "-i", "0", "-o", "L", "-e", "L", "./app", NULL);
error ("execlp");
stdbuf
命令使用 LD_PRELOAD 将库 (libstdbuf.so
) 加载到另一个程序中。这个库做了修改缓冲选项的技巧。您可以避免使用 stdbuf
并在 exec() 之前自行设置预加载选项。您也可以编写自己的库并预加载它。但是使用 stdbuf
可能是最简单的选择,如果你有这个命令可用的话。
这是您的代码的完整修改示例:
//input.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#define WRITE 1
#define READ 0
void error (char *msg)
{
perror (msg);
exit (-1);
}
void got_here (char *msg)
{
printf ("Got_here: %s\n", msg);
}
int main (int argc, char **argv, char **envp)
{
int fd_parent[2];
int fd_child[2]; // for parent and child to write respectively
pid_t child;
if (pipe (fd_parent) < 0) {
error ("pipe(fd_parent)");
}
if (pipe (fd_child) < 0) {
error ("pipe(fd_child)");
}
child = fork ();
if (child < 0) {
error ("fork");
} else if (child == 0) {
dup2 (fd_child[WRITE], STDOUT_FILENO);
dup2 (fd_parent[READ], STDIN_FILENO);
close (fd_parent[WRITE]);
close (fd_child[READ]);
char str[100] = "./app";
char **new_argv = malloc (sizeof (char *) * (argc + 9));
new_argv[0] = "stdbuf";
new_argv[1] = "-i";
new_argv[2] = "0";
new_argv[3] = "-o";
new_argv[4] = "L";
new_argv[5] = "-e";
new_argv[6] = "L";
new_argv[7] = str;
memcpy (&new_argv[8], &argv[1], argc - 1);
new_argv[argc + 8] = NULL;
execvp ("stdbuf", new_argv);
error ("execvp");
close (fd_parent[READ]);
close (fd_child[WRITE]);
return 0;
} else {
close (fd_parent[READ]);
close (fd_child[WRITE]);
FILE *stream = fdopen (fd_child[READ], "r");
FILE *stream_write = fdopen (fd_parent[WRITE], "w");
char str[20];
char menu[4] = "10\n";
int res = fread (str, sizeof (char), 20, stream); // Here is where the problem lies
printf ("res = %d\n", res);
got_here ("after read"); // it does not get here
fwrite (menu, sizeof (char), 3, stream_write);
fflush (stream_write);
fclose (stream);
fclose (stream_write);
printf ("Parent Done\n");
return 0;
}
}
我正在编写代码来与涉及读取和写入应用程序的应用程序进行交互。这是代码:第一个 - 即 input.c 与第二个交互 - 即 app.c
//input.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#define WRITE 1
#define READ 0
void error(char* msg){
perror(msg);
exit(-1);
}
void got_here(char* msg){
printf("Got_here:%s\n",msg);
}
int main(int argc, char** argv, char** envp){
int fd_parent[2];
int fd_child[2]; // for parent and child to write respectively
if(pipe(fd_parent) < 0 | pipe(fd_child) < 0){
error("Fail to create a pipe"); /// just an error-handle function
}
pid_t child = fork();
if(child < 0){
error("Fail to create a child");
}
else if(child == 0){
dup2(fd_child[WRITE], STDOUT_FILENO);
dup2(fd_parent[READ], STDIN_FILENO);
close(fd_parent[WRITE]);
close(fd_child[READ]);
char str[100] = "./app";
execve(str, argv,envp);
close(fd_parent[READ]);
close(fd_child[WRITE]);
return 0;
}
else{
close(fd_parent[READ]);
close(fd_child[WRITE]);
FILE* stream = fdopen(fd_child[READ], "r");
FILE* stream_write = fdopen(fd_parent[WRITE], "w");
char str[20];
char menu[4] = "10\n";
fread(str,sizeof(char), 20, stream); // Here is where the problem lies
got_here("after read"); // it does not get here
fwrite(menu, sizeof(char), 3, stream_write);
fflush(stream_write);
fclose(stream);
fclose(stream_write);
printf("Parent Done\n");
return 0;
}
}
这是应用程序代码(为了缩短代码,我只包括主要内容):
int main(int argc, char** argv, char** envp){
char str[10];
printf("- Select Menu -1\n");
printf("1. Play Lotto\n");
scanf("%s", str);
return 0;
}
在 运行 之后,我的程序只是暂停在 fread()
行,它应该完成对应用程序的读取和写入。有趣的是,如果我在第二个程序中省略 scanf()
或 printf()
,它就可以正常工作。我尝试更改 fwrite
和 fread
的位置,但问题仍然存在。我认为这是与缓冲区相关的问题,但我尝试与之交互的应用程序不允许更改,因此我不能包含 fflush
或其他内容。
我的猜测是对的还是另有解释?以及如何克服这个问题?
您可以使用stdbuf命令修改管道另一端程序的缓冲选项。为了在 C 中执行此操作,您可以编写:
char str[100] = "./app";
char **new_argv = malloc (sizeof (char *) * (argc + 9));
new_argv[0] = "stdbuf";
new_argv[1] = "-i";
new_argv[2] = "0";
new_argv[3] = "-o";
new_argv[4] = "L";
new_argv[5] = "-e";
new_argv[6] = "L";
new_argv[7] = str;
memcpy (&new_argv[8], &argv[1], argc - 1);
new_argv[argc + 8] = NULL;
execvp ("stdbuf", new_argv);
error ("execvp");
或者如果您真的不需要将父项的参数传递给子项,则:
execlp ("stdbuf", "stdbuf", "-i", "0", "-o", "L", "-e", "L", "./app", NULL);
error ("execlp");
stdbuf
命令使用 LD_PRELOAD 将库 (libstdbuf.so
) 加载到另一个程序中。这个库做了修改缓冲选项的技巧。您可以避免使用 stdbuf
并在 exec() 之前自行设置预加载选项。您也可以编写自己的库并预加载它。但是使用 stdbuf
可能是最简单的选择,如果你有这个命令可用的话。
这是您的代码的完整修改示例:
//input.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#define WRITE 1
#define READ 0
void error (char *msg)
{
perror (msg);
exit (-1);
}
void got_here (char *msg)
{
printf ("Got_here: %s\n", msg);
}
int main (int argc, char **argv, char **envp)
{
int fd_parent[2];
int fd_child[2]; // for parent and child to write respectively
pid_t child;
if (pipe (fd_parent) < 0) {
error ("pipe(fd_parent)");
}
if (pipe (fd_child) < 0) {
error ("pipe(fd_child)");
}
child = fork ();
if (child < 0) {
error ("fork");
} else if (child == 0) {
dup2 (fd_child[WRITE], STDOUT_FILENO);
dup2 (fd_parent[READ], STDIN_FILENO);
close (fd_parent[WRITE]);
close (fd_child[READ]);
char str[100] = "./app";
char **new_argv = malloc (sizeof (char *) * (argc + 9));
new_argv[0] = "stdbuf";
new_argv[1] = "-i";
new_argv[2] = "0";
new_argv[3] = "-o";
new_argv[4] = "L";
new_argv[5] = "-e";
new_argv[6] = "L";
new_argv[7] = str;
memcpy (&new_argv[8], &argv[1], argc - 1);
new_argv[argc + 8] = NULL;
execvp ("stdbuf", new_argv);
error ("execvp");
close (fd_parent[READ]);
close (fd_child[WRITE]);
return 0;
} else {
close (fd_parent[READ]);
close (fd_child[WRITE]);
FILE *stream = fdopen (fd_child[READ], "r");
FILE *stream_write = fdopen (fd_parent[WRITE], "w");
char str[20];
char menu[4] = "10\n";
int res = fread (str, sizeof (char), 20, stream); // Here is where the problem lies
printf ("res = %d\n", res);
got_here ("after read"); // it does not get here
fwrite (menu, sizeof (char), 3, stream_write);
fflush (stream_write);
fclose (stream);
fclose (stream_write);
printf ("Parent Done\n");
return 0;
}
}