实验四 匿名管道通信

【实验软硬件环境】

Linux、Win11、GCC

【实验目的与内容】

学习使用匿名管道在两进程间建立通信。

父进程创建一个匿名管道,在父子进程间建立通信

【实验程序及分析】

Windows下

父进程代码father.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <windows.h>
#include <process.h>
#include<stdio.h>

int main() {
HANDLE hParentRead, hParentWrite, hChildRead, hChildWrite;

SECURITY_ATTRIBUTES sa = {0};
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.bInheritHandle = TRUE;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);

if (!CreatePipe(&hParentRead, &hChildWrite, &sa, 0)) {
printf("Pipe failed.");
}
if (!CreatePipe(&hChildRead, &hParentWrite, &sa, 0)) {
printf("Pipe failed.");
}

STARTUPINFO si = {0};
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_SHOWDEFAULT;
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdInput = hChildRead;
si.hStdOutput = hChildWrite;
si.hStdError = HANDLE(STD_ERROR_HANDLE);

PROCESS_INFORMATION pi = {0};

printf("Create child process...");
Sleep(50);
BOOL bSuccess = CreateProcess(TEXT("child.exe"), NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
printf("Send signal? [Y/n]\n");
char ch;
scanf("%c",&ch);
if (ch == 'y' || ch == 'Y') {
printf("Send signal...\n");
Sleep(50);
char buffer[4096] = {'y', 0};
DWORD dwBytesWritten;
if (!WriteFile(hParentWrite, buffer, strlen(buffer) * 2, &dwBytesWritten, NULL)) {
printf("Sent failed");
}
printf("Send success.\n");
Sleep(50);

char result[4096] = {0};
int flag = 0;
while (TRUE) {
memset(result, 0, sizeof(result));
DWORD dwReadSize;
if (!ReadFile(hParentRead, result, 4096, &dwReadSize, NULL)) {
continue;
}
if (result[0] == 'e') {
printf("%s\n", result);
Sleep(50);
if (flag < 5) {
continue;
}
else {
break;
}
}
else {
printf("Received: %s\n", result);
Sleep(50);
++flag;
}
}
printf("Success.");
}
CloseHandle(hParentRead);
CloseHandle(hParentWrite);
CloseHandle(hChildRead);
CloseHandle(hChildWrite);
system("pause");
return 0;
}
子进程代码child.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <windows.h>
#include <process.h>
#include <stdio.h>

int main() {
printf("Child: Started...");
Sleep(50);
HANDLE hRead, hWrite;
hRead = GetStdHandle(STD_INPUT_HANDLE);
hWrite = GetStdHandle(STD_OUTPUT_HANDLE);

HANDLE hFile = CreateFile(TEXT("example.txt"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
printf("Child: Error");
Sleep(50);
CloseHandle(hFile);
}
else {
printf("Child: File handle complete...");
Sleep(50);
printf("Child: Waiting for signal...");
Sleep(50);
TCHAR str[4096] = {0};
DWORD dwReadSize;
while (TRUE) {
memset(str, 0, sizeof(str));

if (!ReadFile(hRead, str, 4096, &dwReadSize, NULL)) {
continue;
}



if ('y' == str[0]) {
printf("Child: Received signal...");
Sleep(50);
FILE *fp = fopen("example.txt", "r");
char s[4096] = {0};
while (fgets(s, 100, fp) != NULL) {
DWORD dwBytesWritten;
WriteFile(hWrite, s, 4096, &dwBytesWritten, NULL);
}
fclose(fp);
break;
}
}
}
printf("Child: Success.");
Sleep(50);
CloseHandle(hRead);
CloseHandle(hWrite);
CloseHandle(hFile);
system("pause");
return 0;
}
代码分析
  1. 创建匿名管道
1
2
3
4
5
6
BOOL CreatePipe( 
PHANDLE hReadPipe, // read handle
PHANDLE hWritePipe, // write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes, // security attributes
DWORD nSize // pipe size
);

参数说明:
hReadPipe:用于存放为匿名管道获取的读句柄。
hWritePipe:用于存放为匿名管道获取的写句柄。
lpPipeAttributes:结构体类型的参数,用于设置管道的属性。
nSize:管道缓冲池的大小,为0时表示默认大小。

【实验截图】

image-20220603155157901

image-20220603155214564

【实验心得体会】

掌握C语言的IO管道通信