лабораторные Тимофеев / 3316_Кирейкова_Лабораторная2
.pdfОткрытие файла. Сначала файл открывается с помощью системного вызова open().
Проецирование в память. Затем с помощью системного
вызова mmap() содержимое файла отображается в виртуальную память процесса. Это создает связь между файлом на диске и областью памяти.
Работа с данными. После проецирования процесс может читать и записывать данные в эту область памяти. Изменения в памяти автоматически синхронизируются с файлом на диске.
Завершение работы. Когда работа с файлом завершена, используется системный вызов munmap() для отключения отображения и функция unlink() для удаления файла.
Код программы
Сервер:
// server.cpp #include <iostream> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <cstring> #include <cstdlib> #include <sys/stat.h> #include <limits>
using namespace std;
#define FILENAME "ProjectedFile" #define FILESIZE 1024
void Create_and_map_file(int &fd, char **ptr) {
fd = open(FILENAME, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1) { perror("Error opening file"); exit(EXIT_FAILURE); }
if (ftruncate(fd, FILESIZE) == -1) { perror("Error setting file size"); close(fd);
exit(EXIT_FAILURE);
}
*ptr = (char *)mmap(nullptr, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (*ptr == MAP_FAILED) { perror("Error mapping file"); close(fd); exit(EXIT_FAILURE);
}
// Ensure file is zeroed initially memset(*ptr, 0, FILESIZE);
cout << "File created and mapped to memory." << endl;
}
11
void WriteToMemory(char *ptr) { string input;
cout << "Enter text (until the empty line):\n"; string line;
while (true) {
if (!getline(cin, line)) break; if (line.empty()) break;
input += line; input += '\n';
}
//Safely copy to mapped memory (reserve one byte for NUL) size_t to_copy = input.size();
if (to_copy > FILESIZE - 1) to_copy = FILESIZE - 1; memcpy(ptr, input.data(), to_copy);
ptr[to_copy] = '\0';
//Make sure changes are flushed to the underlying file if (msync(ptr, FILESIZE, MS_SYNC) == -1) {
perror("msync failed");
}
cout << "Data has been successfully written to memory." << endl;
}
void UnmapAndDeleteFile(int fd, char *ptr) { if (ptr != nullptr) {
if (munmap(ptr, FILESIZE) == -1) { perror("munmap failed");
}
ptr = nullptr;
}
if (fd != -1) { close(fd); fd = -1;
}
// Remove the file from filesystem if (unlink(FILENAME) == -1) {
perror("unlink failed"); } else {
cout << "File unmapped and deleted." << endl;
}
}
int main() { int choice; int fd = -1;
char *ptr = nullptr;
while (true) {
cout << "\nServer Menu:\n";
cout << "1. Execute projection (create & map file)\n"; cout << "2. Write data\n";
cout << "3. Unmap file and delete\n"; cout << "4. Exit\n";
cout << "Choice: ";
if (!(cin >> choice)) { cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n'); cout << "Invalid input.\n";
continue;
}
cin.ignore(); // consume newline
12
switch (choice) { case 1:
if (ptr != nullptr) {
cout << "File already mapped.\n"; } else {
Create_and_map_file(fd, &ptr);
}
break; case 2:
if (ptr != nullptr) { WriteToMemory(ptr);
} else {
cout << "Memory not mapped. Execute projection first." <<
endl;
}
break; case 3:
if (ptr != nullptr || fd != -1) { UnmapAndDeleteFile(fd, ptr); ptr = nullptr;
fd = -1; } else {
cout << "No mapped file to unmap/delete." << endl;
}
break; case 4:
if (ptr != nullptr || fd != -1) { UnmapAndDeleteFile(fd, ptr);
}
cout << "Exiting server." << endl; return 0;
default:
cout << "Invalid choice. Try again." << endl;
}
}
return 0;
}
Клиент:
// client.cpp #include <iostream> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <cstring> #include <cstdlib> #include <chrono> #include <thread>
using namespace std;
#define FILENAME "ProjectedFile"
13
#define FILESIZE 1024
void map_and_read_file() {
int fd = open(FILENAME, O_RDONLY); if (fd == -1) {
perror("Error opening file"); return;
}
char *ptr = (char *)mmap(nullptr, FILESIZE, PROT_READ, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) {
perror("Error mapping file"); close(fd);
return;
}
cout << "File mapped to memory." << endl;
// Простое ожидание данных: опрашиваем содержимое первые 5 секунд const int timeout_seconds = 5;
bool got_data = false;
for (int i = 0; i < timeout_seconds; ++i) {
if (ptr[0] != '\0') { // если первый байт ненулевой — считаем, что данные появились
got_data = true; break;
}
this_thread::sleep_for(chrono::seconds(1));
}
if (!got_data) {
cout << "Timeout: No data available for reading." << endl;
}else {
//Печатаем строку (защищённо, длину ограничиваем FILESIZE)
cout << "Client received:\n";
// ensure null-terminated copy for safe printing
size_t len = strnlen(ptr, FILESIZE);
14
cout.write(ptr, len); cout << endl;
}
if (munmap(ptr, FILESIZE) == -1) { perror("munmap failed");
}
close(fd);
cout << "File unmapped." << endl;
}
int main() { int choice;
while (true) {
cout << "\nClient Menu:\n";
cout << "1. Execute projection and read data\n"; cout << "2. Exit\n";
cout << "Choice: ";
if (!(cin >> choice)) { cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n'); cout << "Invalid input.\n";
continue;
}
switch (choice) { case 1:
map_and_read_file(); break;
case 2:
cout << "Exiting..." << endl; return 0;
default:
cout << "Invalid choice. Try again." << endl;
}
}
15
return 0;
}
Вывод:
В рамках лабораторной работы были разработаны два взаимосвязанных приложения — серверное и клиентское. Сервер отвечал за формирование файла и его настройку для записи данных, в то время как клиент ожидал сигнала о готовности файла и затем осуществлял чтение информации из него.
По завершении работы с файлом была предусмотрена функция его удаления из системы.
Данная реализация наглядно продемонстрировала принципы организации межпроцессного взаимодействия с использованием проецируемых файлов в памяти. Практическая работа позволила углубить понимание механизмов взаимодействия между процессами и освоить особенности управления файлами в рамках клиент-серверной архитектуры.
16
