[英]Is there a clear way of communicate two programs in windows?
我的目标只是以下几点:
将字符串化的 JSON(从我的程序)发送到另一个程序(外部程序)并等待字符串响应,也是字符串化的 JSON。 这与 JSON 编程无关。 我使用的代码(两个程序实际上都是 C++ 程序)是:
void initializePipeCommunication(){
//HANDLE que representa la salida estandar de este programa (DLL). Se conectara con la entrada estandar del otro programa
HANDLE this_write;
//HANDLE que representa la entrada estandar de este programa (DLL).
HANDLE this_read;
//informacion del proceso asociado al programa externo, es necesaria esta variable para cerrar la comunicacion
PROCESS_INFORMATION externalProcessInformation;
//HANDLE que representa la entrada estandar del otro programa.
HANDLE child_input_read;
//HANDLE que representa la salida estandar del otro programa.
HANDLE child_output_write;
STARTUPINFO startup_info;
SECURITY_ATTRIBUTES security_attributes;
// Set the security attributes for the pipe handles created
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
security_attributes.bInheritHandle = TRUE;
security_attributes.lpSecurityDescriptor = NULL;
CreatePipe(&this_read, &child_output_write, &security_attributes, 0);
CreatePipe(&child_input_read, &this_write, &security_attributes, 0);
ZeroMemory(&externalProcessInformation, sizeof(PROCESS_INFORMATION));
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(STARTUPINFO);
startup_info.hStdInput = child_input_read;
startup_info.hStdOutput = child_output_write;
//startup_info.hStdError = child_output_write;
startup_info.dwFlags |= STARTF_USESTDHANDLES;
startup_info.dwFlags |= STARTF_USESHOWWINDOW;
TCHAR* szCommandLine = loadExecutablePathFromRegistryWide();
lstrcatW(szCommandLine, L" UsePipeMode");
//Creando el programa externo
if (!CreateProcess(NULL, szCommandLine, NULL, NULL,
TRUE, 0/*CREATE_NEW_CONSOLE*/, NULL, NULL, &startup_info, &externalProcessInformation)){
DWORD dwStatus = GetLastError();
if (dwStatus == ERROR_CANCELLED || dwStatus == ERROR_ELEVATION_REQUIRED) {
Errors::report(Errors::BAD_EXTERNAL_PROGRAM_PRIVILEGES);
}
else if (dwStatus == ERROR_FILE_NOT_FOUND) {
// The file defined by lpFile was not found and an error message popped up.
Errors::report(Errors::BAD_EXTERNAL_PROGRAM_PATH);
}
PluginHelper::log("error # ");
PluginHelper::logn(std::to_string(dwStatus).c_str());
}}
void write(std::string msg){
unsigned long dwWritten, toWrite = msg.length();
WriteFile(this_write, msg.c_str(), toWrite, &dwWritten, NULL);
}
std::string read(){
unsigned long dwRead, dwWritten;
static char* chBuf = (char*)malloc(266240);
ReadFile(this_read, chBuf, 266240, &dwRead, NULL);
chBuf[dwRead] = 0;
std::string g(chBuf);
return (g.substr(0, g.length()));
}
那就是使用管道,实际上是双方的匿名管道。 我不关心异步通信。
问题是我发送的字符串大约为 266KB,有时来自外部程序的响应带有错误的 JSON 格式,同样,在外部程序中,字符串化的 JSON 构造良好并发送到我的程序(日志证实了这一点)。 总而言之,双方的匿名管道是相同的,在外部程序中,发送到我的程序的字符串很好,除此之外,在我的程序中,响应是我期望的另一个(加上不一致的错误,如连接到没有意义的 JSON)。
有人问:
• 上面的代码是否很好或至少是防错的?
• 是否有输入/输出方式,即cin/cout 通信方式而无需硬欺骗? (就像 Google Chrome 本机消息界面那样)
我从事 Win32 编码已有 20 多年,并编写过服务器、应用程序,应有尽有。 我认为我使用管道的唯一原因是为了方便(但有限的效用)端点的 ACL,或者能够模拟客户端。 否则,它只是专有的,性能不是很好。
至于您报告的损坏,我的猜测是截断,因为您假设所有数据都被一次读取,操作系统既不能保证,也不可能考虑到数据的大小。 我建议修改您的协议以始终首先发送 DWORD dwBytesSent,读取它,然后循环直到您从管道中读取了那么多字节。
如果我是你,因为这些数据听起来好像变大了,我可能会把它写到一个文件中。 您可以使用GetTempFileName()
找出写入位置。 您可以使用应用程序独有的简单前缀来清理孤立文件,例如超过一天的文件。 然后只是简单的(通常至少是同样快的)API 来读/写数据。
如果您想要更高的性能(和复杂性),您可以使用共享内存或套接字。 套接字对于可移植性很好,但有一些额外的开销(环回适配器不是超快),您需要关闭 Nagling: setsockopt(TCP_NODELAY)
。 共享内存并不比您用于管道的 API 难,但性能更高,但您需要在其中发明一个协议(例如,第一个 DWORD 是状态,第二个 DWORD 是长度,其余的是数据)。 微软有一篇很好的教程文章。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.