前言
windows出于安全考虑,进程间的内存是隔离的.数据也是隔离的.所以,两个进程如果需要通信(同一台设备),需要通过其他的方式进行处理.
邮槽
邮槽是一种简单的 IPC 机制,允许一个或多个进程发送消息到一个邮件槽中,其他进程可以从中读取这些消息。
特点:
- 单向通信:邮件槽通常用于单向通信,即数据从发送者流向接收者。
- 不可靠性:邮件槽不保证消息的送达,适合对实时性要求不高的场景。
- 简单易用:实现相对简单,适合快速开发。
服务端
#include <windows.h>
#include <iostream>
int main() {
const char* mailSlotName = "\\\\.\\mailslot\\MyMailSlot";
HANDLE hMailSlot = CreateMailslotA(mailSlotName, 0, MAILSLOT_WAIT_FOREVER, NULL);
if (hMailSlot == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to create mail slot. Error: " << GetLastError() << std::endl;
return 1;
}
std::cout << "Mail Slot created. Waiting for messages..." << std::endl;
char buffer[100];
DWORD bytesRead;
while (true) {
BOOL result = ReadFile(hMailSlot, buffer, sizeof(buffer) - 1, &bytesRead, NULL);
if (result && bytesRead > 0) {
buffer[bytesRead] = '\0'; // Null-terminate the string
std::cout << "Received message: " << buffer << std::endl;
}
}
CloseHandle(hMailSlot);
return 0;
}
客户端
#include <windows.h>
#include <iostream>
int main() {
const char* mailSlotName = "\\\\.\\mailslot\\MyMailSlot";
HANDLE hMailSlot = CreateFileA(mailSlotName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hMailSlot == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open mail slot. Error: " << GetLastError() << std::endl;
return 1;
}
const char* message = "Hello from the client!";
DWORD bytesWritten;
BOOL result = WriteFile(hMailSlot, message, strlen(message) + 1, &bytesWritten, NULL);
if (result) {
std::cout << "Message sent: " << message << std::endl;
} else {
std::cerr << "Failed to send message. Error: " << GetLastError() << std::endl;
}
CloseHandle(hMailSlot);
return 0;
}
匿名管道
匿名管道是一种用于父子进程之间进行通信的机制。它允许一个进程(通常是父进程)创建一个管道,并通过该管道与其子进程进行数据传输。一般用于父进程读取子进程的数据.(也可以双向通信,但只能是父子进程间通信)
特点
- 单向通信:通常为单向,数据从写入端流向读取端。
- 父子进程之间:主要用于父进程与其直接创建的子进程之间的通信。
- 不具名:没有名称,进程通过句柄引用。
- 速度快:由于在同一进程内的内存中操作,速度相对较快。
- 安全性:因为不具名,外部进程无法访问,增加了安全性。
父进程代码
#include <windows.h>
#include <iostream>
int main() {
HANDLE hReadPipe, hWritePipe;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
// 创建管道
if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) {
std::cerr << "Failed to create pipe. Error: " << GetLastError() << std::endl;
return 1;
}
// 创建子进程
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.hStdOutput = hWritePipe;
si.dwFlags |= STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, (LPSTR)"child_process.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
std::cerr << "Failed to create child process. Error: " << GetLastError() << std::endl;
return 1;
}
CloseHandle(hWritePipe); // 关闭写端,父进程只需读
// 读取子进程输出
char buffer[128];
DWORD bytesRead;
while (ReadFile(hReadPipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL) && bytesRead > 0) {
buffer[bytesRead] = '\0'; // Null-terminate the string
std::cout << "Received from child: " << buffer << std::endl;
}
CloseHandle(hReadPipe);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
子进程代码
#include <iostream>
int main() {
std::cout << "Hello from the child process!" << std::endl;
return 0;
}
这段代码是父进程读取子进程的控制台输出.
命名管道
命名管道与匿名管道差不多,区别是命名管道可以在任意的两个进程间进行通信
服务端
#include <windows.h>
#include <iostream>
int main() {
const char* pipeName = "\\\\.\\pipe\\MyNamedPipe";
HANDLE hPipe;
// 创建命名管道
hPipe = CreateNamedPipeA(
pipeName,
PIPE_ACCESS_DUPLEX, // 双向访问
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, // 仅允许一个连接
512, // 输出缓冲区大小
512, // 输入缓冲区大小
0, // 默认超时
NULL
);
if (hPipe == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to create named pipe. Error: " << GetLastError() << std::endl;
return 1;
}
std::cout << "Waiting for client to connect..." << std::endl;
// 等待客户端连接
BOOL connected = ConnectNamedPipe(hPipe, NULL);
if (!connected) {
std::cerr << "Failed to connect to pipe. Error: " << GetLastError() << std::endl;
CloseHandle(hPipe);
return 1;
}
// 读取客户端发送的数据
char buffer[128];
DWORD bytesRead;
if (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL)) {
buffer[bytesRead] = '\0'; // Null-terminate the string
std::cout << "Received from client: " << buffer << std::endl;
// 发送响应回客户端
const char* response = "Hello from server!";
DWORD bytesWritten;
WriteFile(hPipe, response, strlen(response) + 1, &bytesWritten, NULL);
} else {
std::cerr << "Failed to read from pipe. Error: " << GetLastError() << std::endl;
}
CloseHandle(hPipe);
return 0;
}
客户端
#include <windows.h>
#include <iostream>
int main() {
const char* pipeName = "\\\\.\\pipe\\MyNamedPipe";
HANDLE hPipe = CreateFileA(
pipeName,
GENERIC_READ | GENERIC_WRITE, // 读写访问
0, // 不共享
NULL,
OPEN_EXISTING, // 打开现有管道
0,
NULL
);
if (hPipe == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open named pipe. Error: " << GetLastError() << std::endl;
return 1;
}
// 发送数据到服务器
const char* message = "Hello from client!";
DWORD bytesWritten;
WriteFile(hPipe, message, strlen(message) + 1, &bytesWritten, NULL);
// 读取服务器的响应
char buffer[128];
DWORD bytesRead;
if (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL)) {
buffer[bytesRead] = '\0'; // Null-terminate the string
std::cout << "Received from server: " << buffer << std::endl;
} else {
std::cerr << "Failed to read from pipe. Error: " << GetLastError() << std::endl;
}
CloseHandle(hPipe);
return 0;
}
消息队列
服务端
#include <windows.h>
#include <iostream>
int main() {
HANDLE hQueue = CreateMsgQueue(NULL, NULL);
if (hQueue == NULL) {
std::cerr << "Failed to create message queue. Error: " << GetLastError() << std::endl;
return 1;
}
while (true) {
char buffer[256];
DWORD bytesRead;
if (ReadMsgQueue(hQueue, buffer, sizeof(buffer), &bytesRead, NULL, 0)) {
buffer[bytesRead] = '\0';
std::cout << "Received: " << buffer << std::endl;
}
}
CloseMsgQueue(hQueue);
return 0;
}
客户端
#include <windows.h>
#include <iostream>
int main() {
HANDLE hQueue = OpenMsgQueue(NULL, NULL);
if (hQueue == NULL) {
std::cerr << "Failed to open message queue. Error: " << GetLastError() << std::endl;
return 1;
}
const char* message = "Hello from client!";
DWORD bytesWritten;
WriteMsgQueue(hQueue, message, strlen(message) + 1, &bytesWritten, 0);
CloseMsgQueue(hQueue);
return 0;
}
WM_COPYDATA
服务端
#include <windows.h>
#include <iostream>
int main() {
HWND hWnd = FindWindow(NULL, "TargetWindowName"); // 替换为目标窗口的名称
if (hWnd == NULL) {
std::cerr << "Could not find target window. Error: " << GetLastError() << std::endl;
return 1;
}
COPYDATASTRUCT cds;
cds.dwData = 1; // 类型标识
cds.cbData = strlen("Hello from WM_COPYDATA") + 1;
cds.lpData = (PVOID)"Hello from WM_COPYDATA";
SendMessage(hWnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)(LPVOID)&cds);
return 0;
}
客户端
#include <windows.h>
#include <iostream>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_COPYDATA) {
PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
std::cout << "Received: " << (char*)pcds->lpData << std::endl;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int main() {
// 注册窗口类和创建窗口...
// 在消息循环中调用 WindowProc
return 0;
}
共享内存(文件映射)
共享内存与文件映射实现基本一致.
服务端
#include <windows.h>
#include <iostream>
int main() {
const char* sharedMemoryName = "MySharedMemory";
HANDLE hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 256, sharedMemoryName);
if (hMapFile == NULL) {
std::cerr << "Could not create file mapping object. Error: " << GetLastError() << std::endl;
return 1;
}
char* pBuf = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 256);
if (pBuf == NULL) {
std::cerr << "Could not map view of file. Error: " << GetLastError() << std::endl;
CloseHandle(hMapFile);
return 1;
}
strcpy(pBuf, "Hello from server!");
// 等待客户端读取
std::cout << "Press Enter to exit..." << std::endl;
std::cin.get();
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}
客户端
#include <windows.h>
#include <iostream>
int main() {
const char* sharedMemoryName = "MySharedMemory";
HANDLE hMapFile = OpenFileMappingA(FILE_MAP_READ, FALSE, sharedMemoryName);
if (hMapFile == NULL) {
std::cerr << "Could not open file mapping object. Error: " << GetLastError() << std::endl;
return 1;
}
char* pBuf = (char*)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 256);
if (pBuf == NULL) {
std::cerr << "Could not map view of file. Error: " << GetLastError() << std::endl;
CloseHandle(hMapFile);
return 1;
}
std::cout << "Received: " << pBuf << std::endl;
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}
剪切板
服务端
#include <windows.h>
#include <iostream>
int main() {
if (!OpenClipboard(NULL)) {
std::cerr << "Could not open clipboard. Error: " << GetLastError() << std::endl;
return 1;
}
const char* message = "Hello from clipboard!";
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, strlen(message) + 1);
memcpy(GlobalLock(hGlobal), message, strlen(message) + 1);
GlobalUnlock(hGlobal);
SetClipboardData(CF_TEXT, hGlobal);
CloseClipboard();
return 0;
}
客户端
#include <windows.h>
#include <iostream>
int main() {
if (!OpenClipboard(NULL)) {
std::cerr << "Could not open clipboard. Error: " << GetLastError() << std::endl;
return 1;
}
HGLOBAL hGlobal = GetClipboardData(CF_TEXT);
if (hGlobal == NULL) {
std::cerr << "Could not get clipboard data. Error: " << GetLastError() << std::endl;
CloseClipboard();
return 1;
}
char* message = static_cast<char*>(GlobalLock(hGlobal));
if (message != NULL) {
std::cout << "Received from clipboard: " << message << std::endl;
GlobalUnlock(hGlobal);
}
CloseClipboard();
return 0;
}
RPC(Sockets/http)
基于网络协议来通信,可以使用socket,http协议进行网络请求.来进行进程通信
服务端
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib") // 链接WS2_32.lib
int main() {
WSADATA wsaData;
SOCKET serverSocket, clientSocket;
sockaddr_in serverAddr, clientAddr;
int clientAddrSize = sizeof(clientAddr);
// 初始化 Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed. Error: " << WSAGetLastError() << std::endl;
return 1;
}
// 创建套接字
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Socket creation failed. Error: " << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
// 设置服务器地址信息
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY; // 监听所有接口
serverAddr.sin_port = htons(54000); // 端口号
// 绑定套接字
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Bind failed. Error: " << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 开始监听
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
std::cerr << "Listen failed. Error: " << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "Waiting for client connections..." << std::endl;
// 接受客户端连接
clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrSize);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Accept failed. Error: " << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 接收消息
char buffer[256];
int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived > 0) {
buffer[bytesReceived] = '\0'; // Null-terminate the string
std::cout << "Received from client: " << buffer << std::endl;
}
// 关闭套接字
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
return 0;
}
客户端
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib") // 链接WS2_32.lib
int main() {
WSADATA wsaData;
SOCKET clientSocket;
sockaddr_in serverAddr;
// 初始化 Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed. Error: " << WSAGetLastError() << std::endl;
return 1;
}
// 创建套接字
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Socket creation failed. Error: " << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
// 设置服务器地址信息
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(54000); // 端口号
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr); // 服务器地址
// 连接到服务器
if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Connection failed. Error: " << WSAGetLastError() << std::endl;
closesocket(clientSocket);
WSACleanup();
return 1;
}
// 发送消息
const char* message = "Hello from client!";
send(clientSocket, message, strlen(message), 0);
// 关闭套接字
closesocket(clientSocket);
WSACleanup();
return 0;
}
COM (Component Object Model)
使用 COM(组件对象模型)进行进程间通信可以让不同的应用程序和组件相互交互。下面是一个简单的 COM 示例,展示了如何创建一个 COM 服务器和一个 COM 客户端。
服务端
#include <windows.h>
#include <iostream>
#include <comdef.h>
#include <atlbase.h>
#include <atlcomcli.h>
class MyComServer : public IDispatch {
public:
MyComServer() : refCount(1) {}
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) {
if (riid == IID_IUnknown || riid == IID_IDispatch) {
*ppv = static_cast<IDispatch*>(this);
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() {
return InterlockedIncrement(&refCount);
}
STDMETHODIMP_(ULONG) Release() {
ULONG count = InterlockedDecrement(&refCount);
if (count == 0) delete this;
return count;
}
// IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) {
*pctinfo = 0;
return S_OK;
}
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) {
return E_NOTIMPL;
}
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) {
return E_NOTIMPL;
}
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) {
if (dispIdMember == 1) { // Custom method ID
std::cout << "Hello from COM Server!" << std::endl;
return S_OK;
}
return DISP_E_MEMBERNOTFOUND;
}
private:
ULONG refCount;
};
class MyComModule : public ATL::CComModule {
public:
HRESULT Init() {
return CoInitialize(NULL);
}
void Term() {
CoUninitialize();
}
};
MyComModule _Module;
extern "C" HRESULT __declspec(dllexport) DllGetClassObject(REFCLSID clsid, REFIID iid, void** ppv) {
if (clsid == CLSID_NULL) {
*ppv = new MyComServer();
return S_OK;
}
return CLASS_E_CLASSNOTAVAILABLE;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
if (fdwReason == DLL_PROCESS_ATTACH) {
_Module.Init();
} else if (fdwReason == DLL_PROCESS_DETACH) {
_Module.Term();
}
return TRUE;
}
客户端
#include <windows.h>
#include <iostream>
#include <comdef.h>
int main() {
CoInitialize(NULL);
IDispatch* pDispatch = NULL;
CLSID clsid;
HRESULT hr = CLSIDFromProgID(L"YourProgID", &clsid); // Replace with your actual ProgID
if (SUCCEEDED(hr)) {
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void**)&pDispatch);
if (SUCCEEDED(hr)) {
DISPPARAMS params = { NULL, NULL, 0, 0 };
VARIANT result;
VariantInit(&result);
hr = pDispatch->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL, NULL);
if (SUCCEEDED(hr)) {
std::cout << "COM method called successfully." << std::endl;
}
pDispatch->Release();
}
}
CoUninitialize();
return 0;
}
运行步骤
-
编译 COM 服务器:
- 将服务器代码编译为 DLL 文件(例如
MyComServer.dll)。
- 将服务器代码编译为 DLL 文件(例如
-
注册 COM 服务器:
- 使用
regsvr32注册 DLL:regsvr32 MyComServer.dll
- 使用
-
编译 COM 客户端:
- 将客户端代码编译为可执行文件(例如
client.exe)。
- 将客户端代码编译为可执行文件(例如
-
运行客户端:
- 运行
client.exe,它将调用 COM 服务器的方法。
- 运行
事件 (Events)
使用事件(Events)进行进程间通信是一种常见的方式,特别是在 Windows 中。事件可以用来通知一个或多个进程某个特定的事件发生。下面是一个使用 Windows 事件对象的示例,展示了如何在一个进程中设置事件,并在另一个进程中等待该事件的触发。
生产者(事件发送方)
#include <windows.h>
#include <iostream>
int main() {
// 创建一个命名事件
HANDLE hEvent = CreateEventA(NULL, TRUE, FALSE, "MyEvent");
if (hEvent == NULL) {
std::cerr << "CreateEvent failed. Error: " << GetLastError() << std::endl;
return 1;
}
std::cout << "Press Enter to signal the event..." << std::endl;
std::cin.get(); // 等待用户输入
// 触发事件
SetEvent(hEvent);
std::cout << "Event signaled!" << std::endl;
CloseHandle(hEvent);
return 0;
}
消费者
#include <windows.h>
#include <iostream>
int main() {
// 打开命名事件
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, "MyEvent");
if (hEvent == NULL) {
std::cerr << "OpenEvent failed. Error: " << GetLastError() << std::endl;
return 1;
}
std::cout << "Waiting for the event to be signaled..." << std::endl;
// 等待事件
WaitForSingleObject(hEvent, INFINITE);
std::cout << "Event was signaled!" << std::endl;
CloseHandle(hEvent);
return 0;
}
信号量 (Semaphores)
使用信号量(Semaphore)进行进程间通信可以有效地控制对共享资源的访问,确保在多进程环境中对资源的安全访问。以下是一个使用 Windows 信号量的示例,展示了如何在一个进程中创建信号量,并在另一个进程中等待和释放信号量。
生产者
#include <windows.h>
#include <iostream>
int main() {
// 创建一个命名信号量
HANDLE hSemaphore = CreateSemaphoreA(NULL, 1, 1, "MySemaphore");
if (hSemaphore == NULL) {
std::cerr << "CreateSemaphore failed. Error: " << GetLastError() << std::endl;
return 1;
}
std::cout << "Press Enter to signal the semaphore..." << std::endl;
std::cin.get(); // 等待用户输入
// 释放信号量
ReleaseSemaphore(hSemaphore, 1, NULL);
std::cout << "Semaphore signaled!" << std::endl;
CloseHandle(hSemaphore);
return 0;
}
消费者
#include <windows.h>
#include <iostream>
int main() {
// 打开命名信号量
HANDLE hSemaphore = OpenSemaphore(SYNCHRONIZE, FALSE, "MySemaphore");
if (hSemaphore == NULL) {
std::cerr << "OpenSemaphore failed. Error: " << GetLastError() << std::endl;
return 1;
}
std::cout << "Waiting for the semaphore to be signaled..." << std::endl;
// 等待信号量
WaitForSingleObject(hSemaphore, INFINITE);
std::cout << "Semaphore was signaled!" << std::endl;
CloseHandle(hSemaphore);
return 0;
}