簡體   English   中英

在 Windows 中是否有一種明確的方式來通信兩個程序?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM