C++程序和未识别程序之间的双向通信
Two way communication between a C++ program and an unidentified program
我想创建一个 C++ 程序,它可以像标准用户一样启动另一个程序并与之通信。
这是一个基本示例:
比如说,我有任何一种语言的程序 A(例如 Python,但它应该是任何一种程序)。该程序通过带有特定命令(如“./myprogram.exe”或"python ./myprogram.py"或"java ./myprogram.jar")的控制台启动。它等待用户的输入并给出所有先例输入的总和。
示例:
./myprogram.exe
Please enter a numer.
User > 4
4
User > 2
6
User > 9
15
所以程序是有记忆的
现在,我想要的是在 C++ 程序 B 中自动执行用户输入和输出读取。所以我的程序 B 将自动发送输入,在发送另一个输入之前等待另一个程序A给出输出等等... 无需关闭并重新启动程序 A 因为程序 A 有输入记忆。
注意:程序A(已测试)不可更改。我只想在不修改的情况下对其进行基准测试。
你知道我如何进行这样的沟通吗?
谢谢
谢谢你的建议,但我读到 pipe()
、fork()
等只能在 UNIX 环境下工作,而我在 Windows 上工作(抱歉忘了说那...)。
所以在搜索了一下,找到文档并创建了一些代码之后,我终于设法得到了我想要的东西。
WARNING :我为遇到与我相同问题并希望事情正常工作的人提供此解决方案。它可能不安全,它可能不是最好的解决方案,使用它需要您自担风险。请记住,它非常特定于 windows.
#include "iostream"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFSIZE 4096
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hInputFile = NULL;
using namespace std;
void CreateChildProcess(string cmdLine);
void WriteToPipe(string input);
string ReadFromPipe();
void ErrorExit(PTSTR);
int main()
{
SECURITY_ATTRIBUTES saAttr;
cout << "Starting pipes..." << endl;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
cout << "Error : StdoutRd CreatePipe" << endl;
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
cout << "Error : Stdout SetHandleInformation" << endl;
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
cout << "Error : Stdin CreatePipe" << endl;
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
cout << "Error : Stdin SetHandleInformation" << endl;
cout << "Creating child process..." << endl;
CreateChildProcess("python C:/Users/Me/Desktop/Benchmark/test.py");
WriteToPipe("5");
ReadFromPipe();
ReadFromPipe();
getchar();
return 0;
}
void CreateChildProcess(string cmdLine)
{ TCHAR *szCmdline = new TCHAR[cmdLine.size() + 1];
szCmdline[cmdLine.size()] = 0;
std::copy(cmdLine.begin(), cmdLine.end(), szCmdline);
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
{
cout << "Error : CreateProcess" << endl;
}
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
}
void WriteToPipe(string input)
{
DWORD dwWritten;
CHAR chBuf[BUFSIZE];
cout << "> " << input.c_str() << endl;
input += "\n";
if (!WriteFile(g_hChildStd_IN_Wr, input.c_str(), strlen(input.c_str()), &dwWritten, NULL))
{
cout << "Error : WriteFile" << endl;
}
}
string ReadFromPipe()
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
string output = "";
bool flag = false;
for (;;)
{
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if (!bSuccess || dwRead == 0) break;
for (int i = 0; i < dwRead; i++)
{
if (chBuf[i] == '\n')
{
flag = true;
break;
}
output += chBuf[i];
}
if (flag)
{
break;
}
}
cout << "< " << output.c_str() << endl;
return output;
}
而程序 test.py 是:
import sys
sys.stdout.write('Loading module\n')
test = int(input())
sys.stdout.write(str(test+1))
sys.stdout.write('\n')
这样做的目的是将字符串“5\n”发送到test.py 并读取输出(即“6”)。它适用于任何命令,如 java test.jar
或 python test.py
或仅 test.exe
.
void CreateChildProcess(string cmdLine)
允许您使用特定命令行创建子进程。
void WriteToPipe(string input)
允许您向子进程发送任何内容(自动添加 '\n')
string ReadFromPipe()
是一个同步函数,它输出一行子进程的输出(最后一个字符'\n'被自动删除)
这个解决方案部分基于这个有据可查的代码:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
我想创建一个 C++ 程序,它可以像标准用户一样启动另一个程序并与之通信。
这是一个基本示例: 比如说,我有任何一种语言的程序 A(例如 Python,但它应该是任何一种程序)。该程序通过带有特定命令(如“./myprogram.exe”或"python ./myprogram.py"或"java ./myprogram.jar")的控制台启动。它等待用户的输入并给出所有先例输入的总和。
示例:
./myprogram.exe
Please enter a numer.
User > 4
4
User > 2
6
User > 9
15
所以程序是有记忆的
现在,我想要的是在 C++ 程序 B 中自动执行用户输入和输出读取。所以我的程序 B 将自动发送输入,在发送另一个输入之前等待另一个程序A给出输出等等... 无需关闭并重新启动程序 A 因为程序 A 有输入记忆。
注意:程序A(已测试)不可更改。我只想在不修改的情况下对其进行基准测试。
你知道我如何进行这样的沟通吗?
谢谢
谢谢你的建议,但我读到 pipe()
、fork()
等只能在 UNIX 环境下工作,而我在 Windows 上工作(抱歉忘了说那...)。
所以在搜索了一下,找到文档并创建了一些代码之后,我终于设法得到了我想要的东西。
WARNING :我为遇到与我相同问题并希望事情正常工作的人提供此解决方案。它可能不安全,它可能不是最好的解决方案,使用它需要您自担风险。请记住,它非常特定于 windows.
#include "iostream"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFSIZE 4096
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hInputFile = NULL;
using namespace std;
void CreateChildProcess(string cmdLine);
void WriteToPipe(string input);
string ReadFromPipe();
void ErrorExit(PTSTR);
int main()
{
SECURITY_ATTRIBUTES saAttr;
cout << "Starting pipes..." << endl;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
cout << "Error : StdoutRd CreatePipe" << endl;
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
cout << "Error : Stdout SetHandleInformation" << endl;
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
cout << "Error : Stdin CreatePipe" << endl;
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
cout << "Error : Stdin SetHandleInformation" << endl;
cout << "Creating child process..." << endl;
CreateChildProcess("python C:/Users/Me/Desktop/Benchmark/test.py");
WriteToPipe("5");
ReadFromPipe();
ReadFromPipe();
getchar();
return 0;
}
void CreateChildProcess(string cmdLine)
{ TCHAR *szCmdline = new TCHAR[cmdLine.size() + 1];
szCmdline[cmdLine.size()] = 0;
std::copy(cmdLine.begin(), cmdLine.end(), szCmdline);
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
{
cout << "Error : CreateProcess" << endl;
}
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
}
void WriteToPipe(string input)
{
DWORD dwWritten;
CHAR chBuf[BUFSIZE];
cout << "> " << input.c_str() << endl;
input += "\n";
if (!WriteFile(g_hChildStd_IN_Wr, input.c_str(), strlen(input.c_str()), &dwWritten, NULL))
{
cout << "Error : WriteFile" << endl;
}
}
string ReadFromPipe()
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
string output = "";
bool flag = false;
for (;;)
{
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if (!bSuccess || dwRead == 0) break;
for (int i = 0; i < dwRead; i++)
{
if (chBuf[i] == '\n')
{
flag = true;
break;
}
output += chBuf[i];
}
if (flag)
{
break;
}
}
cout << "< " << output.c_str() << endl;
return output;
}
而程序 test.py 是:
import sys
sys.stdout.write('Loading module\n')
test = int(input())
sys.stdout.write(str(test+1))
sys.stdout.write('\n')
这样做的目的是将字符串“5\n”发送到test.py 并读取输出(即“6”)。它适用于任何命令,如 java test.jar
或 python test.py
或仅 test.exe
.
void CreateChildProcess(string cmdLine)
允许您使用特定命令行创建子进程。
void WriteToPipe(string input)
允许您向子进程发送任何内容(自动添加 '\n')
string ReadFromPipe()
是一个同步函数,它输出一行子进程的输出(最后一个字符'\n'被自动删除)
这个解决方案部分基于这个有据可查的代码:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx