Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
9
Добавлен:
26.02.2022
Размер:
144.47 Кб
Скачать

Вариант 3

Задание

Написать программу для обмена сообщениями через механизм Windows Mailstots, которая действует следующим образом:

1.Запрашивает у пользователя наименование почтового ящика и пытается создать его функцией CreateMailslot(), а если почтовый ящик уже существует, получает его описатель функцией CreateFile().

Указание 1. Пользователь должен вводить полное наименование почтового ящика, например, \\.\mailslot\test. Если оно не начинается с \\.\, такой ящик нельзя создать, к нему можно только подключиться (он расположен на удаленной машине). Указание 2. Можно диагностировать, что почтовый ящик существует, если функция CreateMailslot() завершилась ошибкой с соответствующим кодом (который можно получить функцией GetLastError()). Узнать нужный код ошибки можно по MSDN.

2.Запрашивает у пользователя, какое действие следует выполнить:

2.1.Получить информацию о почтовом ящике: количество сообщений, размер последнего сообщения (которое будет извлечено следующим), наибольший допустимый размер сообщения для данного ящика. Сведения необходимо вывести на экран, получив их функцией GetMailslotInfo().

2.2.(Только для процессов-клиентов.) Поместить сообщение в почтовый ящик. Необходимо запросить у пользователя текст сообщения, который может быть многострочным и завершается пустой строкой, а затем записать сообщение в почтовый ящик функцией WriteFile().

2.3.(Только для процесса-сервера.) Получить сообщение из почтового ящика.

Необходимо считать очередное сообщение функцией ReadFile() и отобразить его на экране. 2.4. Завершить работу. Следует отключиться от почтового ящика, закрыв его

описатель функцией CloseHandle().

Указание. По умолчанию созданный функцией CreateMailslot() почтовый ящик

доступен для чтения и записи только ОС (учетной записи LOCAL SYSTEM ). Параметром lpSecurityAttributes можно разрешить доступ всем процессам; код для заполнения структуры SECURITY_ATRIBUTES приведен в приложении.

Проверку работы программ следует выполнять, запуская несколько экземпляров приложения, например, из «Проводника».

Выполнение

#define WINVER 0x0501 #include <windows.h> #include <sddl.h> #include <iostream> #include <memory> #include <string> #include <cstring> #include <cstdlib> #include <clocale>

#define MAX_MSG_SIZE 512

1

//Запрос наименования почтового ящика static std::string GetMailslotPath()

{

static const char name_prefix[] = "\\\\.\\mailslot\\"; std::string result;

bool valid_name = false; do

{

std::cout << "Enter full mailslot path: "; std::getline(std::cin, result);

//Проверка корректности введенного имени if (result.size() < sizeof(name_prefix) ||

strncmp(name_prefix, result.c_str(), sizeof(name_prefix) - 1) != 0)

{

std::cout << "Error. Name must be: " << name_prefix << "name.\n";

}

else

{

valid_name = true;

}

} while (!valid_name); return result;

}

//Разрешение доступа всем процессам

static PSECURITY_DESCRIPTOR CreateSecurityDescriptor()

{

const char* sddl = "D:(A;OICI;GRGW;;;AU)(A;OICI;GA;;;BA)"; PSECURITY_DESCRIPTOR security_descriptor = nullptr; ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, SDDL_REVISION_1,

&security_descriptor, nullptr); return security_descriptor;

}

static SECURITY_ATTRIBUTES CreateSecurityAttributes()

{

SECURITY_ATTRIBUTES attributes; attributes.nLength = sizeof(attributes);

attributes.lpSecurityDescriptor = CreateSecurityDescriptor(); attributes.bInheritHandle = FALSE;

return attributes;

}

//Обработка команд пользователя

void Execute(HANDLE handle, bool is_server)

{

//Пояснения пользователю std::string hint = "Type "

+std::string(is_server ? "'read' to read the next one,\n" : "'write' to write,\n")//Сервер читает сообщения, клиент пишет сообщения

+std::string(is_server ? " 'check' to check for messages,\n" : "")//Просмотр информации доступен только серверу

2

+ " 'quit' to terminate.\n"; std::cout << hint;

std::string cmd; while (true)

{

std::cout << "> "; std::getline(std::cin, cmd);

//Выполнение запроса на завершение работы if (cmd == "quit")

{

break;

}

if (is_server)//Если приложение - сервер

{

//Получение информации о ящике: кол-ва сообщений, размера посл-го сообщения и макс. допустимого размера

DWORD msg_count; DWORD next_size; DWORD max_size;

if (!GetMailslotInfo(handle, &max_size, &next_size, &msg_count, nullptr))

{

std::cout << "Error. Error code: " << GetLastError()<<'\n'; break;

}

//Чтение и отображение очередного сообщения if (cmd == "read")

{

if (msg_count)

{

auto buf = std::make_unique<char[]>(next_size); DWORD read;

if (!ReadFile(handle, buf.get(), next_size, &read, nullptr))

{

std::cout << "Error. Error code: " << GetLastError()<<'\n'; break;

}

std::cout.write(buf.get(), read); std::cout << '\n';

}

else

{

std::cout << "[ OK ] No messages for you, Commander.\n";

}

}

//Отображение информации о входящих сообщениях else if (cmd == "check")

{

3

if (msg_count == 0)

{

std::cout << "[ OK ] No messages for you, Commander\n";

}

else

{

std::cout << "[ OK ] Commander, you have " << msg_count << " new messages on your private terminal.\n";

std::cout << "The size of next message is " << next_size << "B.\n"; std::cout << "The maximum size of a message is " << max_size << "B.\n";

}

}

else

std::cout << "How may I help you, Commander?\n" << hint;

}

else //Если приложение - клиент

{

//Запрос и запись сообщения пользователя if (cmd == "write")

{

std::string message; std::string line;

std::cout << "Enter message text. Terminate with an empty line.\n"; do

{

std::getline(std::cin, line);

if (!line.empty() && !message.empty()) message.append("\r\n");

message.append(line); } while (!line.empty());

DWORD written;

if (!WriteFile(handle, message.c_str(), message.size(), &written, nullptr))

{

std::cout << "Error. Error code: " << GetLastError()<<'\n'; break;

}

else

std::cout << "[ OK ] Message sent.\n";

}

else

std::cout << "How may I help you, Commander?\n" << hint;

}

}

}

int main()

{

setlocale(LC_ALL, "");

bool is_server = true;//Флаг: 1 - сервер, 0 - клиент; после первого запуска - сервер, при

4

следующих запусках - клиент

auto path = GetMailslotPath();

auto sec_attr = CreateSecurityAttributes();

DWORD err = ERROR_SUCCESS;

auto mailslot = CreateMailslot(path.c_str(), MAX_MSG_SIZE, MAILSLOT_WAIT_FOREVER, &sec_attr);//Попытка создания нового почтового ящика

if (mailslot == INVALID_HANDLE_VALUE)

{

err = GetLastError();

//Если ящик уже существует

if (err == ERROR_ALREADY_EXISTS)

{

is_server = false;//Приложение - клиент

mailslot = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);//Получение описателя существующего почтового ящика

err = GetLastError();

}

}

if (err != ERROR_SUCCESS)

{

std::cout << "Error. Error code: " << err <<'\n'; return EXIT_FAILURE;

}

Execute(mailslot, is_server);

LocalFree(sec_attr.lpSecurityDescriptor);

CloseHandle(mailslot);//Закрытие дескриптора почтового ящика return EXIT_SUCCESS;

}

5

Соседние файлы в папке Windows лаб 1-4