进程通信专题
2、管道
1、课程目标
- 理解管道的类型和特点
- 掌握匿名管道和命名管道的使用
- 学会双向通信的实现
- 理解管道在安全领域的应用
2、名词解释
| 术语 | 英文 | 说明 |
|---|---|---|
| 匿名管道 | Anonymous Pipe | 父子进程间的单向通信 |
| 命名管道 | Named Pipe | 可跨进程/网络的双向通信 |
| 消息模式 | Message Mode | 按消息边界读取 |
| 字节模式 | Byte Mode | 按字节流读取 |
3、代码实现
3.1、示例1:匿名管道
#include <windows.h>
#include <stdio.h>
void AnonymousPipeDemo() {
HANDLE hReadPipe, hWritePipe;
SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, TRUE};
// 创建管道
if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) {
printf("CreatePipe failed\n");
return;
}
// 创建子进程
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hReadPipe;
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
TCHAR cmdLine[] = TEXT("child.exe");
CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
// 父进程写入
const char* msg = "Hello from parent";
DWORD written;
WriteFile(hWritePipe, msg, strlen(msg), &written, NULL);
CloseHandle(hWritePipe);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(hReadPipe);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
3.2、示例2:命名管道服务端
#include <windows.h>
#include <stdio.h>
void NamedPipeServer() {
HANDLE hPipe = CreateNamedPipe(
TEXT("\\\\.\\pipe\\MyPipe"),
PIPE_ACCESS_DUPLEX, // 双向
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, // 最大实例数
4096, 4096, // 缓冲区大小
0, // 默认超时
NULL // 安全属性
);
if (hPipe == INVALID_HANDLE_VALUE) {
printf("CreateNamedPipe failed: %d\n", GetLastError());
return;
}
printf("Waiting for client...\n");
// 等待客户端连接
if (ConnectNamedPipe(hPipe, NULL) || GetLastError() == ERROR_PIPE_CONNECTED) {
char buffer[256];
DWORD bytesRead, bytesWritten;
// 读取客户端消息
ReadFile(hPipe, buffer, sizeof(buffer)-1, &bytesRead, NULL);
buffer[bytesRead] = '\0';
printf("Received: %s\n", buffer);
// 发送响应
const char* response = "Hello from server";
WriteFile(hPipe, response, strlen(response), &bytesWritten, NULL);
DisconnectNamedPipe(hPipe);
}
CloseHandle(hPipe);
}
3.3、示例3:命名管道客户端
#include <windows.h>
#include <stdio.h>
void NamedPipeClient() {
HANDLE hPipe;
// 等待管道可用
WaitNamedPipe(TEXT("\\\\.\\pipe\\MyPipe"), NMPWAIT_WAIT_FOREVER);
// 连接管道
hPipe = CreateFile(
TEXT("\\\\.\\pipe\\MyPipe"),
GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
0, NULL
);
if (hPipe == INVALID_HANDLE_VALUE) {
printf("Connect failed: %d\n", GetLastError());
return;
}
// 设置消息模式
DWORD mode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(hPipe, &mode, NULL, NULL);
// 发送消息
const char* message = "Hello from client";
DWORD bytesWritten, bytesRead;
WriteFile(hPipe, message, strlen(message), &bytesWritten, NULL);
// 读取响应
char buffer[256];
ReadFile(hPipe, buffer, sizeof(buffer)-1, &bytesRead, NULL);
buffer[bytesRead] = '\0';
printf("Response: %s\n", buffer);
CloseHandle(hPipe);
}
3.4、示例4:远程管道连接
#include <windows.h>
#include <stdio.h>
void RemotePipeClient(const char* server) {
char pipeName[256];
sprintf(pipeName, "\\\\%s\\pipe\\MyPipe", server);
HANDLE hPipe = CreateFileA(
pipeName,
GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
0, NULL
);
// ... 与本地管道使用相同
}
4、课后作业
- 基础练习:实现父子进程间的管道通信
- 双向通信:使用命名管道实现请求-响应模式
- 多客户端:实现支持多客户端的管道服务端
- 安全应用:分析SMB命名管道的安全风险