问题描述
程序要点:服务器创建n个客户端进程。在客户端用户输入发送到服务器的字符串。在服务器上,字符串的处理方式如下:计算输入字符串中元音和数字出现的频率。此外,此信息被发送到客户端,客户端打印答案
备注:
漏洞要点:服务器成功将应答写入命名管道后,客户端拒绝从管道读取应答。
服务器:
#include <windows.h>
#include <iostream>
#include <tchar.h>
#include <strsafe.h>
#include <limits>
#include <string.h>
#include <sstream>
#pragma warning(disable : 4996)
using namespace std;
#ifdef max
#undef max
#endif
#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096
int main(int argc,char* argv[])
{
// ***ROUTINE STAFF***
cout << "Server is lauched\n"
"It will be terminated when all clients exits\n";
if (argc > 2 || (argc == 2 && argv[argc - 1] != "--help")) {
cout << "Program should be lauched this way:\n"
"name_of_program --help\n"
"Note: --help is optional\n";
return EXIT_FAILURE;
}
if (argc == 2 && argv[argc - 1] == "--help") {
cout << "The server creates n client processes. On the client user\n"
"enters a character string that is sent to the server.On server\n"
"the string is processed as follows : the frequency is counted\n"
"the appearance of vowels and numbers in the entered string.Further,\n"
"this information is sent to the client.\n";
return EXIT_SUCCESS;
}
int n = 0;
cout << "Enter number of clients: ";
if (!(cin >> n) || (n < 0))
{
cout << "Invalid input\n";
return EXIT_FAILURE;
}
cin.ignore(numeric_limits<streamsize>::max(),'\n'); // cleaning buffer
// ***CREATING PROCESSES***
cout << "Generating " << n << " clients...\n";
// struct _STARTUPINFO: Specifies the window station,desktop,standard handles,and appearance of the main window for a process at creation time.
STARTUPINFO* si_arr = new STARTUPINFO[n];
// struct _PROCESS_informatION: Contains information about a newly created process and its primary thread. It is used with the CreateProcess() (and other).
PROCESS_informatION* pi_arr = new PROCESS_informatION[n];
for (int i = 0; i < n; ++i) {
// ZeroMemory macro: Fills a block of memory with zeros.
/*
void ZeroMemory(
[in] PVOID Destination,[in] SIZE_T Length
);
*/
ZeroMemory(&si_arr[i],sizeof(si_arr[i]));
// DWORD STARTUPINFO.cb: The size of the structure,in bytes.
si_arr[i].cb = sizeof(si_arr[i]);
ZeroMemory(&pi_arr[i],sizeof(pi_arr[i]));
if (!CreateProcess(
TEXT("C:\\Users\\andre\\source\\repos\\pipe_client\\Debug\\pipe_client.exe"),// name of program (like in cmd)
NULL,// arguments for program (like in cmd after name of program)
NULL,// Process handle not inheritable
NULL,// Thread handle not inheritable
FALSE,// Set handle inheritance to FALSE
CREATE_NEW_CONSOLE,// dwCreationFlags - The new process gets a new console instead of inheriting the parent one
NULL,// Use parent's environment block
NULL,// Use parent's starting directory
&si_arr[i],// Pointer to STARTUPINFO structure
&pi_arr[i]) // Pointer to PROCESS_informatION structure
)
{
printf("CreateProcess Failed (%d).\n",GetLastError());
return EXIT_FAILURE;
}
}
cout << "All processes (pipe clients) created\n";
// ***CREATING PIPE INSTANCES***
HANDLE* pipe_instances = new HANDLE[n];
for (int i = 0; i < n; i++)
{
pipe_instances[i] = CreateNamedPipe(
TEXT("\\\\.\\pipe\\os_lab4_pipe"),// pipe name
PIPE_ACCESS_DUPLEX,// read/write access
PIPE_TYPE_MESSAGE | // message-type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT,// blocking mode
n,// number of instances
1024,// output buffer size
1024,// input buffer size
PIPE_TIMEOUT,// client time-out
NULL); // default security attributes
if (pipe_instances[i] == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe Failed with %d.\n",GetLastError());
return EXIT_FAILURE;
}
}
cout << "All pipe instances created\n";
// ***CONNECTING PIPE INSTANCES***
for (int i = 0; i < n; i++)
{
if (!ConnectNamedPipe(pipe_instances[i],NULL))
{
printf("ConnectNamedPipe Failed with %d.\n",GetLastError());
return EXIT_FAILURE;
}
}
cout << "All pipe instances connected to clients\n";
// ***PROCESSING***
char buf[1024];
DWORD read_bytes;
DWORD written_bytes;
for (int i = 0; i < n; i++)
{
if (ReadFile(pipe_instances[i],buf,1024,&read_bytes,NULL))
{
char* str = new char[read_bytes];
strncpy(str,read_bytes);
//char answer[1024]; // ready c-str to WriteFile
int total_amount = 0;
int vowel_amount = 0;
int digit_amount = 0;
double vowel_frequency = 0.0;
double digit_frequency = 0.0;
char vowels[] = "aeIoUy";
char digits[] = "0123456789";
total_amount = strlen(str);
printf("Total: %i\n",total_amount);
// vowel
char* vowel_search;
vowel_search = strpbrk(str,vowels); // check for first occurence of vovel in str
while (vowel_search != NULL) { // while vovels not end up in str
vowel_amount++;
vowel_search = strpbrk(vowel_search + 1,vowels);
}
vowel_frequency = (double)vowel_amount / (double)total_amount * 100.0;
// digit
char* digit_search;
digit_search = strpbrk(str,digits); // check for first occurence of digit in str
while (digit_search != NULL) { // while digits not end up in str
digit_amount++;
digit_search = strpbrk(digit_search + 1,digits);
}
digit_frequency = (double)digit_amount / (double)total_amount * 100.0;
string pre_str;
pre_str = "Total: " + to_string(total_amount) + "\n"
"Vowels: " + to_string(vowel_amount) + "\n"
"Frequency: " + to_string(vowel_frequency) + "\n"
"Digits: " + to_string(digit_amount) + "\n"
"Frequency:" + to_string(digit_frequency) + "\n";
cout << pre_str;
const char* answer = pre_str.c_str();
if (!WriteFile(pipe_instances[i],answer,&written_bytes,NULL)) {
printf("WriteFile Failed with %d.\n",GetLastError());
return EXIT_FAILURE;
}
}
else {
printf("ReadFile Failed with %d.\n",GetLastError());
return EXIT_FAILURE;
}
}
cout << "Reading,processing and writting was successful\n";
// ***CLOSING PIPE INSTANCES***
for (int i = 0; i < n; i++)
{
CloseHandle(pipe_instances[i]);
}
// !? - WaitMultipleObjects()
delete[] pipe_instances;
cout << "All pipe instances closed\n";
// ***CLOSING PROCESSES***
// The code written below is needed in order for the server to shutdown not earlier than the clients
HANDLE* ev_hndl_arr = new HANDLE[n];
for (int i = 0; i < n; i++) {
ev_hndl_arr[i] = pi_arr[i].hProcess;
}
// Wait until EACH child process exits.
WaitForMultipleObjects(n,ev_hndl_arr,TRUE,INFINITE);
// Close process and thread handles.
for (int i = 0; i < n; i++) {
CloseHandle(pi_arr[i].hProcess);
CloseHandle(pi_arr[i].hThread);
}
delete[] si_arr;
delete[] pi_arr;
delete[] ev_hndl_arr;
cout << "All processes (pipe clients) closed\n";
cout << "This is the end of server execution\n";
system("pause");
return EXIT_SUCCESS;
}
客户:
#include <iostream>
#include <stdio.h> // fgets()
#include <string.h> // strpbrk()
#include <Windows.h>
using namespace std;
int main() {
cout << "Client is launched\n";
HANDLE hndlNP = CreateFile(
TEXT("\\\\.\\pipe\\os_lab4_pipe"),GENERIC_READ | GENERIC_WRITE,NULL,// Prevents other processes from opening a file or device
NULL,// cannot be inherited by any child processes
OPEN_EXISTING,// no attributes
NULL // no template
);
if (hndlNP == INVALID_HANDLE_VALUE) {
cout << "CreateFile error\n";
return EXIT_FAILURE;
}
cout << "Pipe connection established\n";
char text[1024];
printf("Enter string (max 1023 symbols): ");
fgets(text,stdin);
char answer[1024];
DWORD read_bytes;
DWORD written_bytes;
if (WriteFile(hndlNP,text,NULL)) {
if (ReadFile(hndlNP,NULL)) {
printf("ReadFile Failed with %d.\n",GetLastError());
system("pause"); // TEMPORARY
return EXIT_FAILURE;
}
}
else {
printf("WriteFile Failed with %d.\n",GetLastError());
system("pause"); // TEMPORARY
return EXIT_FAILURE;
}
cout << "Writting and reading was successful\n";
cout << answer;
// ***CLOSING PIPE CONNECTION***
CloseHandle(hndlNP);
system("pause");
return 0;
}
执行示例:
服务器:
Server is lauched
It will be terminated when all clients exits
Enter number of clients : 2
Generating 2 clients...
===Two clients appears===
All processes(pipe clients) created
All pipe instances created
All pipe instances connected to clients
Total : 8
Total : 8
Vowels : 0
Frequency : 0.000000
Digits : 6
Frequency : 75.000000
Total : 6
Total : 6
Vowels : 0
Frequency : 0.000000
Digits : 5
Frequency : 83.333333
Reading,processingand writting was successful
All pipe instances closed
========================== (waiting until clients exit)
This is the end of server execution
Press any key to continue . . .
(key pressed,server closed)
客户端 1:
Client is launched
Pipe connection established
Enter string(max 1023 symbols) : 124345s
ReadFile Failed with 0.
Press any key to continue . . .
==========================
(key pressed,client closed)
客户端 2:
Client is launched
Pipe connection established
Enter string(max 1023 symbols) : 12234
ReadFile Failed with 0.
Press any key to continue . . .
==========================
(key pressed,client closed)
解决方法
如果函数成功,则返回值非零 (TRUE)。
如果函数失败,或者正在异步完成,则返回
值为零 (假)。要获取扩展错误信息,请调用
GetLastError
函数。
所以当ReadFile
返回非零时,函数执行成功,而你的处理错误,你应该修改为:
if (!ReadFile(hndlNP,answer,1024,&read_bytes,NULL)) {
printf("ReadFile failed with %d.\n",GetLastError());
system("pause"); // TEMPORARY
return EXIT_FAILURE;
}