// Программа из конспекта "Системное программное обеспечение" // Файлы, отображаемые на память, синхронизация мьютексами // стр. ?? // Приложение MFM_SERVER (серверное приложение) // Демонстрация использования файлов, отображаемых на память, // для передачи данных между процессами, синхронизированными мьютексами #define _CRT_SECURE_NO_WARNINGS #include #include #include // Идентификаторы объектов-мьютексов, которые используются // для синхронизации задач, принадлежащих разным процессам HANDLE hMutexSend; HANDLE hMutexRecv; HANDLE hMutexTermination; HANDLE hMutexes[2]; // Имя объекта-мьютекса для синхронизации записи и чтения из отображаемого файла CHAR lpMutexSendName[] = "$MyMutexSendName$"; CHAR lpMutexRecvName[] = "$MyMutexRecvName$"; // Имя объекта-мьютекса для завершения процесса CHAR lpMutexTerminationName[] = "$MyMutexTerminationName$"; // Имя отображния файла на память CHAR lpFileShareName[] = "$MyFileShareName$"; // Идентификатор отображения файла на память HANDLE hFileMapping; // Указатель на отображенную область памяти LPVOID lpFileMap; LONG res; LPLONG lpres = &res; int main() { DWORD dwRetCode; CHAR str[80]; FILE* hdl; DWORD cbWritten; DWORD total = 0; // буфер для сообщения об ошибке, результата char message[80] = { 0 }; printf("Mapped and shared file, mutex sync, server process\n"); // Создаем объект-мьютекс для синхронизации // чтения из отображаемого файла hMutexSend = CreateMutex(NULL, FALSE, lpMutexSendName); hMutexRecv = CreateMutex(NULL, FALSE, lpMutexRecvName); // Если произошла ошибка, получаем и отображаем ее код, // а затем завершаем работу приложения if ((hMutexRecv == NULL) || hMutexSend == NULL) { fprintf(stdout, "CreateMutex: Error %ld\n", GetLastError()); _getch(); return 0; } // Если объект-мьютекс с указанным именем существует, // считаем, что приложение-сервер уже было запущено if (GetLastError() == ERROR_ALREADY_EXISTS) { printf("\nServerApplication already started\n" "Press any key to exit..."); _getch(); return 0; } // Создаем объект-отображение, файл не создаем!!! hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 100, lpFileShareName); // Если создать не удалось, выводим код ошибки if (hFileMapping == NULL) { fprintf(stdout, "CreateFileMapping: Error %ld\n", GetLastError()); _getch(); return 0; } // Выполняем отображение файла на память. // В переменную lpFileMap будет записан указатель на // отображаемую область памяти lpFileMap = MapViewOfFile(hFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); // Если выполнить отображение не удалось, // выводим код ошибки if (lpFileMap == 0) { fprintf(stdout, "MapViewOfFile: Error %ld\n", GetLastError()); _getch(); return 0; } // Цикл чтения/записи. Этот цикл завершает свою работу // при завершении процесса-клиента while (TRUE) { total = 0; hMutexTermination = OpenMutex(MUTEX_ALL_ACCESS, FALSE, lpMutexTerminationName); if (hMutexTermination == NULL) { // Если ошибка открытия, то клиента нет, ждем... continue; } fprintf(stdout, "Client working. Waiting data...\n"); // Открываем объект-мьютекс для определения момента // записи процесса ввода и завершения работы процесса ввода // Выполняем ожидание одного из двух событий: // - завершение клиентского процесса; // - завершение записи данных клиентом dwRetCode = WaitForSingleObject(hMutexTermination, 500); // Если дождались сигнала завершения, то выход из цикла, if (dwRetCode == WAIT_OBJECT_0 || dwRetCode == WAIT_FAILED ) break; // блокируем клиента, чтобы ждал ответа dwRetCode = WaitForSingleObject(hMutexRecv, INFINITE); // Читаем данные (имя файла для обработки) из отображенной // области памяти, записанный туда клиентским // процессом, и отображаем его в консольном окне dwRetCode = WaitForSingleObject(hMutexSend, INFINITE); // //else { if (!strcmp((LPSTR)lpFileMap, "")) { // в отображении пусто, клиент отправил Enter ReleaseMutex(hMutexSend); continue; } //puts(((LPSTR)lpFileMap)); sprintf(message, "(Server): Get command:%s\n", (LPSTR)lpFileMap); WriteFile(GetStdHandle(STD_ERROR_HANDLE), message, strlen(message), &cbWritten, NULL); ReleaseMutex(hMutexSend); // обработка данных strcpy(str, ((LPSTR)lpFileMap)); if (!strcmp(str, "exit")) break; str[strlen(str) + 1] = '\n'; total = 0; if (hdl = fopen(str, "rt")) { // цикл чтения до конца файла while (!feof(hdl)) { // чтение одного символа из файла if ((char)fgetc(hdl) == 0x20) total++; } // сообщение в консоль ошибок sprintf(message, "(Server): file:%s, spaces = %d\n", str, total); WriteFile(GetStdHandle(STD_ERROR_HANDLE), message, strlen(message), &cbWritten, NULL); // сообщение в канал sprintf(message, "%d", (int)total); strcpy(((LPSTR)lpFileMap), message); // закрытие файла fclose(hdl); } else { // сообщение в канал sprintf(message, "(Server)Can't open %s!", str); WriteFile(GetStdHandle(STD_ERROR_HANDLE), message, strlen(message) + 1, &cbWritten, NULL); printf("\n"); strcpy(((LPSTR)lpFileMap), message); } // разрешаем читать клиенту ReleaseMutex(hMutexSend); //? ReleaseMutex(hMutexRecv); } } // Закрываем идентификаторы объектов-семафоров CloseHandle(hMutexSend); CloseHandle(hMutexRecv); CloseHandle(hMutexTermination); // Отменяем отображение файла UnmapViewOfFile(lpFileMap); // Освобождаем идентификатор созданного // объекта-отображения CloseHandle(hFileMapping); return 0; }