Windows进程间通信
邮槽
使用邮槽的进程分为服务端和客户端。客户端只能发送消息,服务端只能读取消息,消息的结构和队列类似。
服务端代码示例
cpp
#include <windows.h>
#include <iostream>
int main() {
// 创建邮槽
HANDLE hMailslot = CreateMailslot(
L"\\\\.\\mailslot\\MyMailslot", // 邮槽名称
0, // 无最大消息大小限制
MAILSLOT_WAIT_FOREVER, // 无限等待
NULL // 默认安全属性
);
if (hMailslot == INVALID_HANDLE_VALUE) {
std::cerr << "创建邮槽失败,错误码:" << GetLastError() << std::endl;
return 1;
}
std::cout << "邮槽创建成功,等待消息..." << std::endl;
char buffer[256];
DWORD bytesRead;
// 读取客户端发送的消息
if (ReadFile(hMailslot, buffer, sizeof(buffer), &bytesRead, NULL)) {
buffer[bytesRead] = '\0';
std::cout << "收到消息:" << buffer << std::endl;
}
CloseHandle(hMailslot);
return 0;
}
客户端代码示例
cpp
#include <windows.h>
#include <iostream>
int main() {
// 打开服务端的邮槽
HANDLE hMailslot = CreateFile(
L"\\\\.\\mailslot\\MyMailslot",
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hMailslot == INVALID_HANDLE_VALUE) {
std::cerr << "打开邮槽失败,错误码:" << GetLastError() << std::endl;
return 1;
}
const char* message = "Hello from client!";
DWORD bytesWritten;
// 发送消息
if (WriteFile(hMailslot, message, strlen(message) + 1, &bytesWritten, NULL)) {
std::cout << "消息发送成功" << std::endl;
}
CloseHandle(hMailslot);
return 0;
}
管道
管道的本质是共享内存。
匿名管道
匿名管道只能在父子进程间进行通信,不能在网络间通信,而且数据传输是单向的,只能一端写,另一端读。
cpp
#include <windows.h>
#include <iostream>
#include <string>
int main() {
HANDLE hRead, hWrite;
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
// 创建匿名管道
if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
std::cerr << "创建管道失败" << std::endl;
return 1;
}
// 父进程写入数据
const char* data = "Hello from parent process!";
DWORD bytesWritten;
WriteFile(hWrite, data, strlen(data) + 1, &bytesWritten, NULL);
// 父进程读取数据(同一进程内演示)
char buffer[256];
DWORD bytesRead;
ReadFile(hRead, buffer, sizeof(buffer), &bytesRead, NULL);
buffer[bytesRead] = '\0';
std::cout << "读取到数据:" << buffer << std::endl;
CloseHandle(hRead);
CloseHandle(hWrite);
return 0;
}
命名管道
命名管道可以在任意进程间通信,通信是双向的,任意一端都可读可写,但是在同一时间只能有一端读、一端写。
服务端代码
cpp
#include <windows.h>
#include <iostream>
int main() {
// 创建命名管道
HANDLE hPipe = CreateNamedPipe(
L"\\\\.\\pipe\\MyPipe", // 管道名称
PIPE_ACCESS_DUPLEX, // 双向通信
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, // 最大实例数
512, 512, // 输入输出缓冲区大小
0, NULL // 超时和安全性
);
if (hPipe == INVALID_HANDLE_VALUE) {
std::cerr << "创建命名管道失败" << std::endl;
return 1;
}
std::cout << "等待客户端连接..." << std::endl;
// 等待客户端连接
if (ConnectNamedPipe(hPipe, NULL)) {
char buffer[256];
DWORD bytesRead;
// 读取客户端消息
ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL);
buffer[bytesRead] = '\0';
std::cout << "收到客户端消息:" << buffer << std::endl;
// 回复客户端
const char* reply = "Hello from server!";
DWORD bytesWritten;
WriteFile(hPipe, reply, strlen(reply) + 1, &bytesWritten, NULL);
}
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
return 0;
}
客户端代码
cpp
#include <windows.h>
#include <iostream>
int main() {
// 连接到服务端的命名管道
HANDLE hPipe = CreateFile(
L"\\\\.\\pipe\\MyPipe",
GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
0, NULL
);
if (hPipe == INVALID_HANDLE_VALUE) {
std::cerr << "连接命名管道失败" << std::endl;
return 1;
}
// 发送消息
const char* message = "Hello from client!";
DWORD bytesWritten;
WriteFile(hPipe, message, strlen(message) + 1, &bytesWritten, NULL);
// 接收回复
char buffer[256];
DWORD bytesRead;
ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL);
buffer[bytesRead] = '\0';
std::cout << "收到服务端回复:" << buffer << std::endl;
CloseHandle(hPipe);
return 0;
}
剪贴板
剪贴板是Windows提供的一种简单的进程间通信机制,所有进程都可以访问系统剪贴板,实现数据的共享和传递。
cpp
#include <windows.h>
#include <iostream>
#include <cstring>
// 写入文本到剪贴板
bool WriteToClipboard(const char* text) {
if (!OpenClipboard(NULL)) {
return false;
}
// 清空剪贴板
EmptyClipboard();
// 分配全局内存
size_t size = strlen(text) + 1;
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, size);
if (hGlobal == NULL) {
CloseClipboard();
return false;
}
// 复制数据到全局内存
memcpy(GlobalLock(hGlobal), text, size);
GlobalUnlock(hGlobal);
// 设置剪贴板数据
SetClipboardData(CF_TEXT, hGlobal);
CloseClipboard();
return true;
}
// 从剪贴板读取文本
std::string ReadFromClipboard() {
if (!OpenClipboard(NULL)) {
return "";
}
HANDLE hData = GetClipboardData(CF_TEXT);
if (hData == NULL) {
CloseClipboard();
return "";
}
char* text = static_cast<char*>(GlobalLock(hData));
std::string result(text);
GlobalUnlock(hData);
CloseClipboard();
return result;
}
int main() {
// 写入剪贴板
const char* data = "Hello from Process A!";
if (WriteToClipboard(data)) {
std::cout << "数据已写入剪贴板" << std::endl;
}
// 读取剪贴板
std::string readData = ReadFromClipboard();
std::cout << "从剪贴板读取:" << readData << std::endl;
return 0;
}
内存映射文件
内存映射文件允许不同进程将同一个文件映射到各自的虚拟地址空间,从而实现高效的共享内存通信。
cpp
#include <windows.h>
#include <iostream>
#include <cstring>
int main() {
// 创建或打开文件映射对象
HANDLE hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // 使用系统分页文件
NULL, // 默认安全属性
PAGE_READWRITE, // 读写权限
0, // 高32位大小
256, // 低32位大小(256字节)
L"Local\\MySharedMemory" // 映射对象名称
);
if (hMapFile == NULL) {
std::cerr << "创建文件映射失败" << std::endl;
return 1;
}
// 将文件映射到进程地址空间
LPVOID pBuffer = MapViewOfFile(
hMapFile,
FILE_MAP_ALL_ACCESS, // 完全访问权限
0, 0, // 偏移量
0 // 映射整个文件
);
if (pBuffer == NULL) {
std::cerr << "映射视图失败" << std::endl;
CloseHandle(hMapFile);
return 1;
}
// 写入共享内存
const char* message = "Hello from Process A!";
memcpy(pBuffer, message, strlen(message) + 1);
std::cout << "数据已写入共享内存" << std::endl;
// 读取共享内存(另一个进程也可以读取)
std::cout << "从共享内存读取:" << (char*)pBuffer << std::endl;
// 清理资源
UnmapViewOfFile(pBuffer);
CloseHandle(hMapFile);
return 0;
}
Socket
Socket(套接字)是Windows中最强大的进程间通信方式之一,不仅支持本地进程通信,还支持网络间的远程通信。
cpp
#include <winsock2.h>
#include <iostream>
#include <cstring>
#pragma comment(lib, "ws2_32.lib")
int main() {
// 初始化Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "Winsock初始化失败" << std::endl;
return 1;
}
// 创建套接字
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "创建套接字失败" << std::endl;
WSACleanup();
return 1;
}
// 绑定地址和端口
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8888);
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "绑定失败" << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 监听连接
listen(serverSocket, 5);
std::cout << "服务器启动,等待连接..." << std::endl;
// 接受客户端连接
sockaddr_in clientAddr;
int clientLen = sizeof(clientAddr);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientLen);
if (clientSocket != INVALID_SOCKET) {
char buffer[256];
recv(clientSocket, buffer, sizeof(buffer), 0);
std::cout << "收到客户端消息:" << buffer << std::endl;
const char* reply = "Hello from server!";
send(clientSocket, reply, strlen(reply), 0);
closesocket(clientSocket);
}
closesocket(serverSocket);
WSACleanup();
return 0;
}