我正在尝试与一个进程进行通信(它本身写入到标准input和标准输出与用户在一个terminal进行交互),并读取它的标准input,并写入它的标准输出在C.
因此,我尝试以编程方式replaceshell用户。 一个美好的例子:想象一下,我想用C中的VIM出于某种原因。 然后我还需要编写命令(stdout)并从编辑器(stdin)读取内容。
起初,我认为这可能是一个微不足道的任务,但似乎没有标准的方法。 int system(const char *command); 只是执行一个命令,并将命令stdin / stdout设置为调用进程的一个。
因为这无处可去,所以我查看了FILE *popen(const char *command,const char *type); 但手册页指出:
是否有可能在编译时间(当天)和date?
如何编写写入/ var / log / myapp目录的C / C ++应用程序?
什么是一个明智的方式让服务器侦听客户端连接将会很less(在Linux上的套接字编程)
是否有一个类似于NUnit的C ++unit testing库?
如何在c ++中获得linux命令的输出string和输出状态
由于pipe道的定义是单向的,所以types参数可以只指定读或写,而不是两者; 所得到的stream是相应的只读或只写。
其含义是:
popen()的返回值在所有方面都是标准的I / Ostream,除了它必须用pclose()而不是fclose(3)来closures。 写入这样的stream写入命令的标准input; 该命令的标准输出 与调用popen()的进程 的标准输出 相同 ,除非这个命令本身被改变了。 相反, 从“popened”stream中读取命令的标准输出 , 命令的标准input与调用popen()的过程相同 。
因此,使用popen()并不是完全不可能的,但是在我看来,这是非常不雅观的,因为我将不得不parsing调用进程(称为popen()的代码)的stdout,以便parsing从被指挥的命令(当使用popen型'w'时)。
相反,当用'r'types调用popen时,我需要写入调用的进程stdin,以便将数据写入到被调用的命令中。 在这种情况下,我不清楚这两个进程是否在标准input接收相同的数据…
我只需要控制程序的stdin和stdout。 我的意思是不能有这样的function:
stdin_of_process,stdout_of_process = real_popen("/path/to/bin","rw") // write some data to the process stdin write("hello",stdin_of_process) // read the response of the process read(stdout_of_process)
所以我的第一个问题是 :什么是实现上层function的最佳方式?
用int pipe(int fildes[2]);设置两个pipe道int pipe(int fildes[2]); 。 一个pipe道读取进程的标准输出,另一个pipe道写入进程的标准input。
叉子。
使用int execvp(const char *file,char *const argv[]);执行我想要在分叉的subprocess中进行通信的进程int execvp(const char *file,char *const argv[]); 。
在原始stream程中使用两个pipe道与小孩沟通。
机器人并不那么简单(至less对我来说)很简单。 我奇怪地设法在一个案例中做到这一点,但是当我用一个简单的例子试图理解我在做什么的时候,我失败了。 这是我目前的问题:
我有两个程序。 第一个每100毫秒写一个递增的数字给它的stdout:
#include <unistd.h> #include <time.h> #include <stdint.h> #include <stdio.h> #include <string.h> void sleepMs(uint32_t ms) { struct timespec ts; ts.tv_sec = 0 + (ms / 1000); ts.tv_nsec = 1000 * 1000 * (ms % 1000); nanosleep(&ts,NULL); } int main(int argc,char *argv[]) { long int cnt = 0; char buf[0x10] = {0}; while (1) { sleepMs(100); sprintf(buf,"%ldn",++cnt); if (write(STDOUT_FILENO,buf,strlen(buf)) == -1) perror("write"); } }
现在第二个程序应该读取第一个程序的标准输出(请记住,我最终希望读取和写入一个进程,所以一个技术正确的解决scheme使用popen()作为上层用例可能是正确的在这个特定的情况下,因为我简化了我的实验,只是捕获底层程序的标准输出)。 我期望从底层程序读取上层程序写入标准输出的任何数据。 但它什么都不读。 原因何在? (第二个问题)。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <stdint.h> #include <time.h> void sleepMs(uint32_t ms) { struct timespec ts; ts.tv_sec = 0 + (ms / 1000); ts.tv_nsec = 1000 * 1000 * (ms % 1000); nanosleep(&ts,NULL); } int main() { int pipe_fds[2]; int n; char buf[0x100] = {0}; pid_t pid; pipe(pipe_fds); char *cmd[] = {"/path/to/program/above",NULL}; if ((pid = fork()) == 0) { /* child */ dup2(pipe_fds[1],1); // set stdout of the process to the write end of the pipe execvp(cmd[0],cmd); // execute the program. fflush(stdout); perror(cmd[0]); // only reached in case of error exit(0); } else if (pid == -1) { /* Failed */ perror("fork"); exit(1); } else { /* parent */ while (1) { sleepMs(500); // Wait a bit to let the child program run a little printf("Trying to readn"); if ((n = read(pipe_fds[0],0x100)) >= 0) { // Try to read stdout of the child process from the read end of the pipe buf[n] = 0; /* terminate the string */ fprintf(stderr,"Got: %s",buf); // this should print "1 2 3 4 5 6 7 8 9 10 ..." } else { fprintf(stderr,"read Failedn"); perror("read"); } } } }
如何避免将sql_BINARY数组数据作为parameter passing时终止? (ODBC驱动程序)
在struct cpu_set_t和struct位掩码之间进行转换
C#Windows 10通用应用程序 – MVVM刷新
Xlib:调整包含像素图的窗口大小
Windows Phone 7空数据消息的列表框?
这是一个(C ++ 11风格)完整的例子。
但是,对于许多实际用途, Expect库可能是一个不错的选择(请查看其源代码分发example子目录中的代码)。
你有正确的想法,我没有时间分析所有的代码来指出具体的问题,但是我想指出一些你可能忽略的有关程序和终端工作的东西。
终端作为一个“文件”的想法是naivé。 像vi这样的程序使用库(ncurses)来发送特殊控制字符(并更改终端设备驱动程序设置)。 例如,vi将终端设备驱动程序本身置于可以一次读取字符的模式中,等等。
像这样控制vi这样的程序是非常不平凡的。
在您的简化实验…
你的缓冲区是一个字节太小。 另外,请注意IO有时是行缓冲的。 所以,你可以尝试确保新行被转移(使用printf而不是sprintf / strlen / write …你已经将stdout挂钩到你的管道上了),否则在命中新行之前你可能看不到数据。 我不记得管线缓冲,但它是值得一试。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。