使用C ++在Windows中进行双向父子通讯 [英] Two way parent child communication in windows with c++
问题描述
向下滚动以查看新更新
更新::换句话说:我想在Windows上以Shell的方式启动另一个程序.
需要在Windows上使用c ++在父进程和子进程之间进行双向通信.父母是我的程序,孩子是一个随机的控制台应用程序(如mysql终端).
Need a two way communication between parent and child process using c++ on Windows. The parent is my program and the child is a random console application (like mysql terminal).
搜索已经进行了几天,但找不到适用于Windows的任何有效解决方案.此外,MS文档也无济于事.
It's been a couple days searching but couldn't find any working solution for Windows. Also MS documentations is not helping.
在这里,我从三年前提出的一个问题中获得了示例代码.如何将代码转换为Microsoft特定的api并在Windows上使用?
Here i got a sample code from a question asked three years ago. How can i translate the code to Microsoft specific api and use it on Windows?
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define Read 0
#define Write 1
#define ParentRead read_pipe[1]
#define ParentWrite write_pipe[0]
#define ChildRead write_pipe[1]
#define ChildWrite read_pipe[0]
int main()
{
int data_processed;
/** Pipe for reading for subprocess */
int read_pipe[2];
/** Pipe for writing to subprocess */
int write_pipe[2];
char buffer[100];
memset(buffer, '\0', 100);
if (pipe(read_pipe) == 0 && pipe(write_pipe) == 0)
{
pid_t pid = fork();
if (pid == (pid_t)-1)
{
fprintf(stderr, "Fork failure");
exit(EXIT_FAILURE);
}
else if (pid == (pid_t)0) //Child process
{
close(Read);
close(Write);
close(ParentRead);
close(ParentWrite);
dup(ChildRead);
dup(ChildWrite);
execlp("cat", (char*)NULL);
exit(EXIT_FAILURE);
}
else { //Parent process
close(ChildRead);
close(ChildWrite);
write(ParentWrite, "abc", 3);
int r = read(ParentRead, buffer, 99);
printf("%d %d", r, errno);
puts(buffer);
}
}
exit(EXIT_SUCCESS);
}
新更新:
因此基于此示例我编写了示例代码的修改版本,但看起来还可以,只是重定向的输出与预期的不一样.这是代码:
So based on this sample I wrote a modified version of the sample code and seems to be OK except that the redirected output is not what it's supposed to be. Here's the code:
#include <iostream>
#include <Windows.h>
#include <string>
HANDLE hSTD_IN_READ = NULL;
HANDLE hSTD_IN_WRITE = NULL;
HANDLE hSTD_OUT_READ = NULL;
HANDLE hSTD_OUT_WRITE = NULL;
void WriteToPipe(std::string);
void ReadFromPipe();
int main()
{
SECURITY_ATTRIBUTES sa;
std::cout << "\nStart of parent execution: ";
// Set the bInheritHandle flag so pipe handles are inherited.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
// Create pip for child process stdout
if (!CreatePipe(&hSTD_OUT_READ, &hSTD_OUT_WRITE, &sa, 0)) {
std::cout << "Error: CreatePipe STDOUT.\n";
return -1;
}
// Ensure the read handle to the pipe for stdout is not inherited.
if (!SetHandleInformation(hSTD_OUT_READ, HANDLE_FLAG_INHERIT, 0)) {
std::cout << "Error: STD_OUT_READ CreatePipe.\n";
return -1;
}
// Create pipe for child process's stdin
if (!CreatePipe(&hSTD_IN_READ, &hSTD_IN_WRITE, &sa, 0)) {
std::cout << "Error: CreatePipe STDIN.\n";
return -1;
}
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(hSTD_IN_WRITE, HANDLE_FLAG_INHERIT, 0)) {
std::cout << "Error: STD_IN_WRITE CreatePipe.\n";
return -1;
}
// Create Child Process
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL bSuccess = FALSE;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
// This structure specifies the STDIN and STDOUT handles for redirection.
si.cb = sizeof(STARTUPINFO);
si.hStdError = hSTD_OUT_WRITE;
si.hStdInput = hSTD_IN_READ;
si.hStdOutput = hSTD_OUT_WRITE;
si.dwFlags |= STARTF_USESTDHANDLES;
bSuccess = CreateProcess(TEXT("c:\\sqlite3.exe"), NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
if (!bSuccess) {
std::cout << "Error in CreateProcess.\n";
return -1;
}
else {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
// Now execute your command then read the child process's output.
WriteToPipe(".databases");
ReadFromPipe();
std::cout << "End of program.\n";
return 0;
}
void WriteToPipe(std::string buffer)
{
DWORD bWritten, BUFFSIZE = buffer.size();
BOOL bSuccess = FALSE;
bSuccess = WriteFile(hSTD_IN_WRITE, buffer.c_str(), BUFFSIZE, &bWritten, NULL);
if (!bSuccess)
std::cout << "WritetoPipe::Couldn't Write to std_in_write.\n";
// Close the pipe handle so the child process stops reading.
if (!CloseHandle(hSTD_IN_WRITE))
std::cout << "WriteToPipe::Couldn't close the handle after Writing to std_in_write.\n";
}
void ReadFromPipe()
{
DWORD bRead, bWritten;
const DWORD BUFFSIZE = 4096;
CHAR buffer[BUFFSIZE];
BOOL bSuccess = FALSE;
HANDLE hPARENT_STD_OUT = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;) {
bSuccess = ReadFile(hSTD_OUT_READ, buffer, BUFFSIZE, &bRead, NULL);
if (!bSuccess || bRead == 0) {
std::cout << "ReadFromPipe::Exiting after ReadFile.\n";
break;
}
bSuccess = WriteFile(hPARENT_STD_OUT, buffer, BUFFSIZE, &bWritten, NULL);
if (!bSuccess) {
std::cout << "ReadFromPipe::Exiting after WriteFile.\n";
break;
}
}
}
输出:
Start of parent execution: seq name file
--- --------------- ----------------------------------------------------------
0 main
ówVE_■ öΘ/ P╞ów (┴M (┴M êΘ/ (┴M £Θ/ ╕å¥w M áΘ/ ,╟₧w Ω/ fr#u M ╝îíw@r#u╕ (∞/ @∩/ ΣΘ/ @ @∩/ (∞/ ⁿΘ/ ép#u@∩/ (∞/ @∩/ <ε/ o#u(∞/ @∩/ 8∩/ 4o#u┘╥₧w ╓ ┤Ω/ ┘jƒw M A÷₧w M A÷₧wÿìM ■≤₧w╪½└( M 8┘M M A÷₧wÿìM ² ¿½└(ªfM M ~fM xçM δ/ M A÷₧wxêM ■≤₧wx¼└( M ╚½└( M δ/ ù wáw Vδ/ ╓ |δ/ ┘jƒwⁿδ/ Vδ/ ½└(αφ/ ⁿδ/
kƒw
kƒw ⁿδ/ ░δ/ (° M ╚╜M ΦÉM îM Ç ÉìM └ 3 6 9 5 7 \ ╨φ/ |δ/ πlƒw╢êM ¿δ/ \ αφ/ ^ ¼φ/ πiƒw╨φ/ áδ/ `ε/ ≥iƒw ┐M \ ^ ¿δ/ S - M A÷₧wÿêM ■≤₧wP¡└(p M h 1 6 2 2 ╠ ╔8 0 - 3 6 9 5 7 ╠ ╔8 1 4 - öfM 0 1 &▄₧w B· A÷₧w ÿêM c : ┘╥₧w@¡└( M ÉêM ╠ ╔ M ╠ ╔ê├M äM Ç ╨∞/ ╠ ╔φ/ Ä╘Γ á∞/
╬M \φ/ φ/ \φ/ ╠ ╔=· zφ/ M ÉêM ñÉM ≡∞/ Ç ë½w┬ǃwL |φ/ ÿêM └& ê╤M ╕∞/ / ówVE_■ dφ/ P╞ów ÿêM ÿêM ╕φ/ á∩/ ÿêM `M S B _ E tφ/ ,╟₧w ÿêM °∩/ @X#u M ÿêM ɱ/ SX#áwɱ/ ┐M DZ/ P P6*uá∩/ ÿêM WΓF┼CÑ■ ìεπ╙≡WΓF┼CÑ■ ìεπ╙≡ _╩╝H±/ ñU#u DZ/ t⌠/ ▒U#u
( ┘╥₧w╨▒└(┘╥₧w╪▒└( M ┐M ╚▒└( M ░╛M ≈ NM ╠ ╔ α╛M M ░╛M ± ▒X#u ░╛M Ç Ç (╟M ╕╛M ╠ └ M L ëM ╕╛M ÿêM ╪ÅM ╪ÅM `M ówVE_■ ▄±/ P╞ów ┐M M ╕╛M ┐M ╕╛M α±/ ╕╛M Φ±/ ,╟₧w ⁿ±/ ?ñ#u M ┐M ╚≈/ ╚≈/ g⌡Θv╩ê∞v╬∩Θv╪D╔@┬Q┌ P_$u ╬ ╧ ╨ ╤ ╥ ╙ ╘ ╒ ╓ ╫ ╪ ┘ ┌ █ ▄ ▌ ▐ ▀ α ß Γ π Σ σ αëM â É▀█ D 'M ö É É l@ L é£ " ┐M ? α² √ @┤└(└ └ M + M > > M └ M M ░ & & M H ñ ¿ @ ≡² α² á& `°/ £ t h╝M + █ [ h @ M P°/ ┐M ╨⌡/ α² ╨& °█ ¿ ██ ╕╛M
¿ ■≤₧ └( ñ ╕╛M °█ c └ M █ █' └ M Ω X╝M & └ ■ ┘╥₧wá £ £ t └ M Ç @ @ ñ °█ $ & Φ╛M ╠⌠v î÷/ á÷/ PΩ¥w╠⌠vî÷/ H⌠v |⌠vH⌠v ⌠v▌Θ¥w░÷/ └≈/ ≤τ¥w┬Q┌ ÿ Φ¥w 2 ⌠v ⌠v ì °≈/ H⌠v ⌠╢└(∞≈/ ┤ïΘv½½½½╝îíw╪ïΘvÿ ┬Q┌ φïΘv░┌ ÿ ⁿD╔@°/ ╩┌ ÿ ■┌
┌S╙╫∞°/ Φå█ ┤°/ 8┌ .databas
推荐答案
As said by Christopher Oicles in the referenced link, the logic using WinAPI is the same:
- 您首先创建用于输入和输出的管道-WinAPI函数是
CreatePipe
- WinAPI允许保护句柄以被继承,因为您没有
fork + exec
来关闭子级中的任何内容-您必须使用SetHandleInformation(handle,HANDLE_FLAG_INHERIT,0);
创建子进程之前 - 使用
CreateProcess
创建子进程,将句柄传递到上面在hStdInput
,hStdOutput
和字段中创建的管道.
-不要忘记声明要与同一结构中的STARTUPINFO
结构的hStdErrordwFlags | = STARTF_USESTDHANDLES;
一起使用.
- you first create pipes for input and output - the WinAPI function is
CreatePipe
- WinAPI allows to protect a handle for being inherited, because you do not have the
fork+exec
to close anything in the child - you must useSetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
before creating the child process - you create the child process with
CreateProcess
, passing the handles to the pipes created above in the fieldshStdInput
,hStdOutput
andhStdError
of theSTARTUPINFO
struct - do not forget to declare that you want to use them withdwFlags |= STARTF_USESTDHANDLES;
in same struct.
这仅对控制台应用程序子项有意义,因为GUI子系统应用程序通常不使用标准流,但可以通过 ftp
命令正常工作.简而言之,当您自己处理流时,系统不会创建控制台,子进程的输出仅在父进程中可用.
This only makes sense with console application childs, because GUI subsystem application normally do not use standard streams, but it will work fine with the ftp
command. Simply, as you process the streams yourself, the system do not create a console and the output from the child process is only available in the parent process.
在您的代码中,至少有一个很好的理由不编写您期望的内容.在 ReadFromPipe
中,您在缓冲区中获得了 bRead
字节,但是您尝试输出完整的缓冲区.
In your code, there is at least one good reason for not writing what you expect. In ReadFromPipe
, you get bRead
bytes in your buffer, but you try to output the full buffer.
输出命令应为:
bSuccess = WriteFile(hPARENT_STD_OUT, buffer, bRead, &bWritten, NULL);
但这还不是全部.命令的终止应与输入文件中的终止相同,即使用 \ r \ n
,因此您的命令应为:
But that is not all. A command should be terminated the same that it would be in a input file, that is with \r\n
, so your command should be:
WriteToPipe(".databases\r\n");
最后但并非最不重要的一点是,您必须在启动子命令后关闭管道的未使用部分,至少要关闭 hSTD_OUT_WRITE
以允许 ReadFile(hSTD_OUT_READ,...)
子进程退出后立即返回0.因此您的代码应为:
And last but not least, you must close the unused parts of the pipes after starting child command, at least hSTD_OUT_WRITE
to allow ReadFile(hSTD_OUT_READ, ...)
to return 0 as soon as the child process exits. So your code should be:
CloseHandle(hSTD_OUT_WRITE);
CloseHandle(hSTD_IN_READ);
// Now execute your command then read the child process's output.
...
通过这些修改,我可以成功地与 ftp.exe
程序进行通信.
With those modifications, I could successfully communicate with the ftp.exe
program.
这篇关于使用C ++在Windows中进行双向父子通讯的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!