From 8c368eb956f9d04ce23d8656d7f5f22145cd222e Mon Sep 17 00:00:00 2001 From: vainmoon Date: Thu, 6 Feb 2025 23:09:27 +0300 Subject: [PATCH 1/2] add lab_01 --- Umnov.Sergei/lab_01/build.sh | 10 ++ Umnov.Sergei/lab_01/config.txt | 2 + Umnov.Sergei/lab_01/daemon.cpp | 203 +++++++++++++++++++++++++++ Umnov.Sergei/lab_01/main.cpp | 33 +++++ Umnov.Sergei/lab_01/test1/sample.txt | 1 + Umnov.Sergei/lab_01/test1/temp.py | 1 + Umnov.Sergei/lab_01/test2/sample.py | 1 + Umnov.Sergei/lab_01/test2/sample1.py | 1 + Umnov.Sergei/lab_01/test2/temp.txt | 1 + 9 files changed, 253 insertions(+) create mode 100755 Umnov.Sergei/lab_01/build.sh create mode 100644 Umnov.Sergei/lab_01/config.txt create mode 100644 Umnov.Sergei/lab_01/daemon.cpp create mode 100644 Umnov.Sergei/lab_01/main.cpp create mode 100644 Umnov.Sergei/lab_01/test1/sample.txt create mode 100644 Umnov.Sergei/lab_01/test1/temp.py create mode 100644 Umnov.Sergei/lab_01/test2/sample.py create mode 100644 Umnov.Sergei/lab_01/test2/sample1.py create mode 100644 Umnov.Sergei/lab_01/test2/temp.txt diff --git a/Umnov.Sergei/lab_01/build.sh b/Umnov.Sergei/lab_01/build.sh new file mode 100755 index 0000000..d907d41 --- /dev/null +++ b/Umnov.Sergei/lab_01/build.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +rm -f daemon + +g++ -Wall -Werror -o daemon main.cpp daemon.cpp +if [ $? -eq 0 ]; then + echo "Build successful" +else + echo "Build failed" +fi diff --git a/Umnov.Sergei/lab_01/config.txt b/Umnov.Sergei/lab_01/config.txt new file mode 100644 index 0000000..44d12a1 --- /dev/null +++ b/Umnov.Sergei/lab_01/config.txt @@ -0,0 +1,2 @@ +/home/vinetiger/study/Operating-Systems-labs-2024/Umnov.Sergei/lab_01/test1 txt +/home/vinetiger/study/Operating-Systems-labs-2024/Umnov.Sergei/lab_01/test2 py \ No newline at end of file diff --git a/Umnov.Sergei/lab_01/daemon.cpp b/Umnov.Sergei/lab_01/daemon.cpp new file mode 100644 index 0000000..0659c3d --- /dev/null +++ b/Umnov.Sergei/lab_01/daemon.cpp @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +class Daemon { +public: + static Daemon& getInstance() { + static Daemon instance; + return instance; + } + + void setConfigFilePath(const std::string& path) { + configFilePath = path; + } + + void reloadConfig() { + syslog(LOG_INFO, "Reloading configuration file"); + readConfigFile(); + } + + void stop() { + syslog(LOG_INFO, "Daemon is stopping"); + closelog(); + removePidFile(); + exit(0); + } + + void start() { + checkAndTerminateExistingDaemon(); + daemonize(); + handleSignals(); + readConfigFile(); + writePidFile(); + + while (true) { + for (const auto& config : folderConfigs) { + processFolder(config.folderPath, config.extension); + } + sleep(interval); + } + } + + Daemon(const Daemon&) = delete; + Daemon& operator=(const Daemon&) = delete; + +private: + Daemon() : interval(30), pid(0), pidFilePath("/tmp/daemon.pid") { + openlog("daemon", LOG_PID | LOG_CONS, LOG_DAEMON); + } + + ~Daemon() { + closelog(); + removePidFile(); + } + + void removePidFile() { + std::remove(pidFilePath.c_str()); + } + + void daemonize() { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != nullptr) { + currentWorkingDir = std::string(cwd); + } + else { + syslog(LOG_ERR, "Failed to get current working directory"); + } + + pid = fork(); + if (pid < 0) { + syslog(LOG_ERR, "Fork failed"); + exit(1); + } + if (pid > 0) { + exit(0); + } + + umask(0); + setsid(); + + if (chdir("/") < 0) { + syslog(LOG_ERR, "Chdir failed"); + exit(1); + } + + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + open("/dev/null", O_RDONLY); + open("/dev/null", O_RDWR); + open("/dev/null", O_RDWR); + } + + void handleSignals() { + signal(SIGHUP, [](int) { Daemon::getInstance().reloadConfig(); }); + signal(SIGTERM, [](int) { Daemon::getInstance().stop(); }); + } + + void readConfigFile() { + std::ifstream configFile(configFilePath); + if (!configFile.is_open()) { + syslog(LOG_ERR, "Failed to open config file: %s", configFilePath.c_str()); + exit(1); + } + + std::string line; + while (std::getline(configFile, line)) { + std::istringstream iss(line); + std::string folderPath, extension; + if (iss >> folderPath >> extension) { + folderConfigs.push_back({folderPath, extension}); + } + } + + configFile.close(); + } + + void processFolder(const std::string& folderPath, const std::string& extension) { + try { + for (const auto& entry : fs::directory_iterator(folderPath)) { + if (entry.is_regular_file()) { + std::string filename = entry.path().filename().string(); + if (filename.substr(filename.find_last_of(".") + 1) == extension) { + logFileDetails(folderPath, filename); + } + } + } + } catch (const fs::filesystem_error& e) { + std::cerr << "Failed to open directory: " << folderPath << " - " << e.what() << std::endl; + } + } + + void logFileDetails(const std::string& folderPath, const std::string& filename) { + std::string filePath = folderPath + "/" + filename; + struct stat fileStat; + if (stat(filePath.c_str(), &fileStat) == 0) { + char timeBuffer[80]; + struct tm *timeInfo = localtime(&fileStat.st_mtime); + strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", timeInfo); + + syslog(LOG_INFO, "Folder: %s, File: %s, Size: %ld bytes, Last Modified: %s", + folderPath.c_str(), filename.c_str(), fileStat.st_size, timeBuffer); + } else { + syslog(LOG_ERR, "Failed to get stats for file: %s", filePath.c_str()); + } + } + + void checkAndTerminateExistingDaemon() { + std::ifstream pidFile(pidFilePath); + if (pidFile.is_open()) { + pid_t existingPid; + pidFile >> existingPid; + pidFile.close(); + + if (kill(existingPid, 0) == 0) { + syslog(LOG_INFO, "Terminating existing daemon with PID %d", existingPid); + kill(existingPid, SIGTERM); + sleep(1); + } + } + } + + void writePidFile() { + std::ofstream pidFile(pidFilePath); + if (pidFile.is_open()) { + pidFile << getpid(); + pidFile.close(); + } + else { + syslog(LOG_ERR, "Failed to write PID file"); + } + } + + struct FolderConfig { + std::string folderPath; + std::string extension; + }; + + std::vector folderConfigs; + std::string configFilePath; + int interval; + pid_t pid; + std::string pidFilePath; + std::string currentWorkingDir; +}; \ No newline at end of file diff --git a/Umnov.Sergei/lab_01/main.cpp b/Umnov.Sergei/lab_01/main.cpp new file mode 100644 index 0000000..78f31b2 --- /dev/null +++ b/Umnov.Sergei/lab_01/main.cpp @@ -0,0 +1,33 @@ +#include "daemon.cpp" +#include +#include +#include + + + +int main(int argc, char* argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + char configFilePath[PATH_MAX]; + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != nullptr) { + std::string fullPath = std::string(cwd) + "/" + argv[1]; + if (realpath(fullPath.c_str(), configFilePath) == nullptr) { + std::cerr << "Error: Cannot resolve config file path: " << argv[1] << std::endl; + return 1; + } + } + else { + std::cerr << "Error: Cannot get current working directory" << std::endl; + return 1; + } + + Daemon& daemon = Daemon::getInstance(); + daemon.setConfigFilePath(configFilePath); + daemon.start(); + + return 0; +} \ No newline at end of file diff --git a/Umnov.Sergei/lab_01/test1/sample.txt b/Umnov.Sergei/lab_01/test1/sample.txt new file mode 100644 index 0000000..72c046c --- /dev/null +++ b/Umnov.Sergei/lab_01/test1/sample.txt @@ -0,0 +1 @@ +Bruh \ No newline at end of file diff --git a/Umnov.Sergei/lab_01/test1/temp.py b/Umnov.Sergei/lab_01/test1/temp.py new file mode 100644 index 0000000..cc12003 --- /dev/null +++ b/Umnov.Sergei/lab_01/test1/temp.py @@ -0,0 +1 @@ +print('Bruh') \ No newline at end of file diff --git a/Umnov.Sergei/lab_01/test2/sample.py b/Umnov.Sergei/lab_01/test2/sample.py new file mode 100644 index 0000000..e0369f7 --- /dev/null +++ b/Umnov.Sergei/lab_01/test2/sample.py @@ -0,0 +1 @@ +print('test') \ No newline at end of file diff --git a/Umnov.Sergei/lab_01/test2/sample1.py b/Umnov.Sergei/lab_01/test2/sample1.py new file mode 100644 index 0000000..e0369f7 --- /dev/null +++ b/Umnov.Sergei/lab_01/test2/sample1.py @@ -0,0 +1 @@ +print('test') \ No newline at end of file diff --git a/Umnov.Sergei/lab_01/test2/temp.txt b/Umnov.Sergei/lab_01/test2/temp.txt new file mode 100644 index 0000000..72c046c --- /dev/null +++ b/Umnov.Sergei/lab_01/test2/temp.txt @@ -0,0 +1 @@ +Bruh \ No newline at end of file From 94a75ee687f7400d02ff197e7e54a8f9b1531f88 Mon Sep 17 00:00:00 2001 From: vainmoon Date: Fri, 7 Feb 2025 15:06:23 +0300 Subject: [PATCH 2/2] add lab_02 --- Umnov.Sergei/lab_02/CMakeLists.txt | 91 +++++++++++++++++++ Umnov.Sergei/lab_02/build.sh | 23 +++++ .../lab_02/src/client/client_fifo.cpp | 35 +++++++ Umnov.Sergei/lab_02/src/client/client_gui.cpp | 67 ++++++++++++++ Umnov.Sergei/lab_02/src/client/client_gui.hpp | 40 ++++++++ Umnov.Sergei/lab_02/src/client/client_mq.cpp | 35 +++++++ Umnov.Sergei/lab_02/src/client/client_seg.cpp | 35 +++++++ .../lab_02/src/connections/conn_fifo.cpp | 49 ++++++++++ .../lab_02/src/connections/conn_fifo.hpp | 24 +++++ .../lab_02/src/connections/conn_mq.cpp | 55 +++++++++++ .../lab_02/src/connections/conn_mq.hpp | 22 +++++ .../lab_02/src/connections/conn_seg.cpp | 49 ++++++++++ .../lab_02/src/connections/conn_seg.hpp | 24 +++++ Umnov.Sergei/lab_02/src/host/host_fifo.cpp | 41 +++++++++ Umnov.Sergei/lab_02/src/host/host_gui.cpp | 67 ++++++++++++++ Umnov.Sergei/lab_02/src/host/host_gui.hpp | 40 ++++++++ Umnov.Sergei/lab_02/src/host/host_mq.cpp | 41 +++++++++ Umnov.Sergei/lab_02/src/host/host_seg.cpp | 41 +++++++++ 18 files changed, 779 insertions(+) create mode 100644 Umnov.Sergei/lab_02/CMakeLists.txt create mode 100644 Umnov.Sergei/lab_02/build.sh create mode 100644 Umnov.Sergei/lab_02/src/client/client_fifo.cpp create mode 100644 Umnov.Sergei/lab_02/src/client/client_gui.cpp create mode 100644 Umnov.Sergei/lab_02/src/client/client_gui.hpp create mode 100644 Umnov.Sergei/lab_02/src/client/client_mq.cpp create mode 100644 Umnov.Sergei/lab_02/src/client/client_seg.cpp create mode 100644 Umnov.Sergei/lab_02/src/connections/conn_fifo.cpp create mode 100644 Umnov.Sergei/lab_02/src/connections/conn_fifo.hpp create mode 100644 Umnov.Sergei/lab_02/src/connections/conn_mq.cpp create mode 100644 Umnov.Sergei/lab_02/src/connections/conn_mq.hpp create mode 100644 Umnov.Sergei/lab_02/src/connections/conn_seg.cpp create mode 100644 Umnov.Sergei/lab_02/src/connections/conn_seg.hpp create mode 100644 Umnov.Sergei/lab_02/src/host/host_fifo.cpp create mode 100644 Umnov.Sergei/lab_02/src/host/host_gui.cpp create mode 100644 Umnov.Sergei/lab_02/src/host/host_gui.hpp create mode 100644 Umnov.Sergei/lab_02/src/host/host_mq.cpp create mode 100644 Umnov.Sergei/lab_02/src/host/host_seg.cpp diff --git a/Umnov.Sergei/lab_02/CMakeLists.txt b/Umnov.Sergei/lab_02/CMakeLists.txt new file mode 100644 index 0000000..4984292 --- /dev/null +++ b/Umnov.Sergei/lab_02/CMakeLists.txt @@ -0,0 +1,91 @@ +cmake_minimum_required(VERSION 3.10) + +# Проект +project(LocalChatApp) + +# Стандарт C++ +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") + +# Путь для поиска Qt6 +set(CMAKE_PREFIX_PATH "/usr/lib/x86_64-linux-gnu/cmake/Qt6") + +# Находим Qt6 и нужные компоненты +find_package(Qt6 REQUIRED COMPONENTS Widgets) + +# Пути для исходников и заголовков +include_directories(src/connections src/host src/client) + +# Определяем пути до заголовочных файлов и используем moc с ними +qt6_wrap_cpp(MOC_SOURCES + src/host/host_gui.hpp + src/client/client_gui.hpp +) + +# Определяем исходники для FIFO +set(HOST_FIFO_SRC_FILES + src/host/host_fifo.cpp + src/connections/conn_fifo.cpp + src/host/host_gui.cpp +) + +set(CLIENT_FIFO_SRC_FILES + src/client/client_fifo.cpp + src/connections/conn_fifo.cpp + src/client/client_gui.cpp +) + +# Определяем исходники для очередей сообщений +set(HOST_QUEUE_SRC_FILES + src/host/host_mq.cpp + src/connections/conn_mq.cpp + src/host/host_gui.cpp +) + +set(CLIENT_QUEUE_SRC_FILES + src/client/client_mq.cpp + src/connections/conn_mq.cpp + src/client/client_gui.cpp +) + +# Определяем исходники для разделяемой памяти +set(HOST_SHM_SRC_FILES + src/host/host_seg.cpp + src/connections/conn_seg.cpp + src/host/host_gui.cpp +) + +set(CLIENT_SHM_SRC_FILES + src/client/client_seg.cpp + src/connections/conn_seg.cpp + src/client/client_gui.cpp +) + +# Определяем цели для FIFO +add_executable(host_fifo ${HOST_FIFO_SRC_FILES} ${MOC_SOURCES}) +add_executable(client_fifo ${CLIENT_FIFO_SRC_FILES} ${MOC_SOURCES}) + +# Определяем цели для очередей сообщений +add_executable(host_mq ${HOST_QUEUE_SRC_FILES} ${MOC_SOURCES}) +add_executable(client_mq ${CLIENT_QUEUE_SRC_FILES} ${MOC_SOURCES}) + +# Определяем цели для разделяемой памяти +add_executable(host_seg ${HOST_SHM_SRC_FILES} ${MOC_SOURCES}) +add_executable(client_seg ${CLIENT_SHM_SRC_FILES} ${MOC_SOURCES}) + +# Привязка библиотек Qt6 +target_link_libraries(host_fifo Qt6::Widgets) +target_link_libraries(client_fifo Qt6::Widgets) +target_link_libraries(host_mq Qt6::Widgets) +target_link_libraries(client_mq Qt6::Widgets) +target_link_libraries(host_seg Qt6::Widgets) +target_link_libraries(client_seg Qt6::Widgets) + +# Путь для исполняемых файлов +set_target_properties(host_fifo PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set_target_properties(client_fifo PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set_target_properties(host_mq PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set_target_properties(client_mq PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set_target_properties(host_seg PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set_target_properties(client_seg PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) diff --git a/Umnov.Sergei/lab_02/build.sh b/Umnov.Sergei/lab_02/build.sh new file mode 100644 index 0000000..96976f6 --- /dev/null +++ b/Umnov.Sergei/lab_02/build.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Удаляем старые файлы сборки +echo "Удаляем старую директорию сборки..." +rm -rf build + +# Создаём новую директорию сборки +echo "Создаём директорию сборки..." +mkdir build + +# Переходим в директорию сборки +cd build || { echo "Ошибка: не удалось перейти в директорию сборки."; exit 1; } + +# Запускаем CMake +echo "Запускаем CMake..." +cmake .. || { echo "Ошибка при запуске cmake."; exit 1; } + +# Компилируем проект +echo "Компиляция проекта..." +make -j$(nproc) || { echo "Ошибка при компиляции."; exit 1; } + +# Завершаем +echo "Сборка завершена успешно. Исполняемые файлы находятся в 'build/bin'." diff --git a/Umnov.Sergei/lab_02/src/client/client_fifo.cpp b/Umnov.Sergei/lab_02/src/client/client_fifo.cpp new file mode 100644 index 0000000..521fd8d --- /dev/null +++ b/Umnov.Sergei/lab_02/src/client/client_fifo.cpp @@ -0,0 +1,35 @@ +#include "conn_fifo.hpp" +#include +#include +#include +#include + +int main() { + try { + ConnFifo conn(1, false); // Подключаемся как клиент + std::cout << "[FIFO Client] Initialized and running..." << std::endl; + + while (true) { + std::string input; + std::cout << "[FIFO Client] Enter message (type 'exit' to quit): "; + std::getline(std::cin, input); + + if (input == "exit") { + conn.Write(input.c_str(), input.size() + 1); + break; + } + + conn.Write(input.c_str(), input.size() + 1); + + char buffer[1024] = {0}; + conn.Read(buffer, sizeof(buffer)); + std::cout << "[FIFO Client] Response: " << buffer << std::endl; + } + } catch (const std::exception &e) { + std::cerr << "[FIFO Client] Error: " << e.what() << std::endl; + return 1; + } + + std::cout << "[FIFO Client] Shutting down..." << std::endl; + return 0; +} diff --git a/Umnov.Sergei/lab_02/src/client/client_gui.cpp b/Umnov.Sergei/lab_02/src/client/client_gui.cpp new file mode 100644 index 0000000..0cf68e0 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/client/client_gui.cpp @@ -0,0 +1,67 @@ +#include "client_gui.hpp" +#include +#include + +ClientGUI::ClientGUI(QWidget *parent) + : QMainWindow(parent) + , clientSegConn(1, false) + , clientMqConn(1, false) + , clientFifoConn(1, false) + , activityTimer(new QTimer(this)) { + + centralWidget = new QWidget(this); + layout = new QVBoxLayout(centralWidget); + + chatDisplay = new QTextEdit(centralWidget); + messageInput = new QLineEdit(centralWidget); + sendButton = new QPushButton("Send", centralWidget); + + layout->addWidget(chatDisplay); + layout->addWidget(messageInput); + layout->addWidget(sendButton); + + setCentralWidget(centralWidget); + + connect(sendButton, &QPushButton::clicked, this, &ClientGUI::onSendButtonClicked); + connect(activityTimer, &QTimer::timeout, this, &ClientGUI::checkActivity); + + activityTimer->start(60000); // Таймер на 1 минуту +} + +ClientGUI::~ClientGUI() { + delete layout; + delete centralWidget; +} + +void ClientGUI::onSendButtonClicked() { + QString message = messageInput->text(); + if (!message.isEmpty()) { + sendMessage(message); + messageInput->clear(); + activityTimer->start(60000); // Перезапуск таймера + } +} + +void ClientGUI::sendMessage(const QString &message) { + QByteArray messageData = message.toUtf8(); + clientSegConn.Write(messageData.constData(), messageData.size()); + clientMqConn.Write(messageData.constData(), messageData.size()); + clientFifoConn.Write(messageData.constData(), messageData.size()); +} + +void ClientGUI::receiveMessage() { + char buffer[1024]; + clientSegConn.Read(buffer, sizeof(buffer)); + chatDisplay->append(QString::fromUtf8(buffer)); + + clientMqConn.Read(buffer, sizeof(buffer)); + chatDisplay->append(QString::fromUtf8(buffer)); + + clientFifoConn.Read(buffer, sizeof(buffer)); + chatDisplay->append(QString::fromUtf8(buffer)); +} + +void ClientGUI::checkActivity() { + QMessageBox::warning(this, "Inactivity", "No messages sent in the last minute. Terminating client."); + QApplication::quit(); +} diff --git a/Umnov.Sergei/lab_02/src/client/client_gui.hpp b/Umnov.Sergei/lab_02/src/client/client_gui.hpp new file mode 100644 index 0000000..fce602e --- /dev/null +++ b/Umnov.Sergei/lab_02/src/client/client_gui.hpp @@ -0,0 +1,40 @@ +#ifndef CLIENT_GUI_HPP +#define CLIENT_GUI_HPP + +#include +#include +#include +#include +#include +#include +#include "conn_seg.hpp" +#include "conn_mq.hpp" +#include "conn_fifo.hpp" + +class ClientGUI : public QMainWindow { + Q_OBJECT + +public: + ClientGUI(QWidget *parent = nullptr); + ~ClientGUI(); + +public slots: + void onSendButtonClicked(); + void checkActivity(); + +private: + QTextEdit *chatDisplay; + QLineEdit *messageInput; + QPushButton *sendButton; + QVBoxLayout *layout; + QWidget *centralWidget; + ConnSeg clientSegConn; + ConnMq clientMqConn; + ConnFifo clientFifoConn; + QTimer *activityTimer; + + void sendMessage(const QString &message); + void receiveMessage(); +}; + +#endif // CLIENT_GUI_HPP diff --git a/Umnov.Sergei/lab_02/src/client/client_mq.cpp b/Umnov.Sergei/lab_02/src/client/client_mq.cpp new file mode 100644 index 0000000..8894a73 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/client/client_mq.cpp @@ -0,0 +1,35 @@ +#include "conn_mq.hpp" +#include +#include +#include +#include + +int main() { + try { + ConnMq conn(1, false); // Подключаемся как клиент + std::cout << "[MQ Client] Initialized and running..." << std::endl; + + while (true) { + std::string input; + std::cout << "[MQ Client] Enter message (type 'exit' to quit): "; + std::getline(std::cin, input); + + if (input == "exit") { + conn.Write(input.c_str(), input.size() + 1); + break; + } + + conn.Write(input.c_str(), input.size() + 1); + + char buffer[1024] = {0}; + conn.Read(buffer, sizeof(buffer)); + std::cout << "[MQ Client] Response: " << buffer << std::endl; + } + } catch (const std::exception &e) { + std::cerr << "[MQ Client] Error: " << e.what() << std::endl; + return 1; + } + + std::cout << "[MQ Client] Shutting down..." << std::endl; + return 0; +} diff --git a/Umnov.Sergei/lab_02/src/client/client_seg.cpp b/Umnov.Sergei/lab_02/src/client/client_seg.cpp new file mode 100644 index 0000000..07abf3d --- /dev/null +++ b/Umnov.Sergei/lab_02/src/client/client_seg.cpp @@ -0,0 +1,35 @@ +#include "conn_seg.hpp" +#include +#include +#include +#include + +int main() { + try { + ConnSeg conn(1, false); // Подключаемся как клиент + std::cout << "[SHM Client] Initialized and running..." << std::endl; + + while (true) { + std::string input; + std::cout << "[SHM Client] Enter message (type 'exit' to quit): "; + std::getline(std::cin, input); + + if (input == "exit") { + conn.Write(input.c_str(), input.size() + 1); + break; + } + + conn.Write(input.c_str(), input.size() + 1); + + char buffer[1024] = {0}; + conn.Read(buffer, sizeof(buffer)); + std::cout << "[SHM Client] Response: " << buffer << std::endl; + } + } catch (const std::exception &e) { + std::cerr << "[SHM Client] Error: " << e.what() << std::endl; + return 1; + } + + std::cout << "[SHM Client] Shutting down..." << std::endl; + return 0; +} diff --git a/Umnov.Sergei/lab_02/src/connections/conn_fifo.cpp b/Umnov.Sergei/lab_02/src/connections/conn_fifo.cpp new file mode 100644 index 0000000..5d89ca7 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/connections/conn_fifo.cpp @@ -0,0 +1,49 @@ +#include "conn_fifo.hpp" +#include +#include + +ConnFifo::ConnFifo(int id, bool create) : id(id), create(create) { + // Генерация уникального пути + fifoPath = "/tmp/myfifo_" + std::to_string(id); + + if (create) { + // Создание FIFO + if (mkfifo(fifoPath.c_str(), 0666) == -1 && errno != EEXIST) { + throw std::runtime_error("Failed to create FIFO: " + std::string(strerror(errno))); + } + } + + // Открытие FIFO + fifo = open(fifoPath.c_str(), O_RDWR); + if (fifo == -1) { + throw std::runtime_error("Failed to open FIFO: " + std::string(strerror(errno))); + } +} + +void ConnFifo::Read(char *buf, size_t count) { + ssize_t bytesRead = read(fifo, buf, count); + if (bytesRead == -1) { + throw std::runtime_error("Read error: " + std::string(strerror(errno))); + } + buf[bytesRead] = '\0'; // Завершающий нулевой символ +} + +void ConnFifo::Write(const char *buf, size_t count) { + ssize_t bytesWritten = write(fifo, buf, count); + if (bytesWritten == -1) { + throw std::runtime_error("Write error: " + std::string(strerror(errno))); + } +} + +ConnFifo::~ConnFifo() { + if (fifo != -1) { + close(fifo); + } + + // Удаление FIFO только если объект его создавал + if (create) { + if (unlink(fifoPath.c_str()) == -1) { + std::cerr << "Failed to unlink FIFO: " << strerror(errno) << std::endl; + } + } +} diff --git a/Umnov.Sergei/lab_02/src/connections/conn_fifo.hpp b/Umnov.Sergei/lab_02/src/connections/conn_fifo.hpp new file mode 100644 index 0000000..e3cc57f --- /dev/null +++ b/Umnov.Sergei/lab_02/src/connections/conn_fifo.hpp @@ -0,0 +1,24 @@ +#ifndef CONN_FIFO_HPP +#define CONN_FIFO_HPP + +#include +#include +#include +#include +#include + +class ConnFifo { +public: + ConnFifo(int id, bool create); + void Read(char *buf, size_t count); + void Write(const char *buf, size_t count); + ~ConnFifo(); + +private: + int id; + bool create; + int fifo; + std::string fifoPath; +}; + +#endif // CONN_FIFO_HPP diff --git a/Umnov.Sergei/lab_02/src/connections/conn_mq.cpp b/Umnov.Sergei/lab_02/src/connections/conn_mq.cpp new file mode 100644 index 0000000..d27a4e9 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/connections/conn_mq.cpp @@ -0,0 +1,55 @@ +#include "conn_mq.hpp" +#include +#include +#include +#include + +ConnMq::ConnMq(int id, bool create) : id(id), create(create) { + // Генерация уникального имени очереди + queueName = "/myqueue_" + std::to_string(id); + + if (create) { + // Создание очереди + struct mq_attr attr = {}; + attr.mq_flags = 0; // Блокирующий режим + attr.mq_maxmsg = 10; // Максимальное количество сообщений + attr.mq_msgsize = 1024; // Максимальный размер сообщения + + mq = mq_open(queueName.c_str(), O_CREAT | O_RDWR, 0644, &attr); + if (mq == (mqd_t)-1) { + throw std::runtime_error("Failed to create message queue: " + std::string(strerror(errno))); + } + } else { + // Открытие существующей очереди + mq = mq_open(queueName.c_str(), O_RDWR); + if (mq == (mqd_t)-1) { + throw std::runtime_error("Failed to open message queue: " + std::string(strerror(errno))); + } + } +} + +void ConnMq::Read(char *buf, size_t count) { + ssize_t bytesRead = mq_receive(mq, buf, count, nullptr); + if (bytesRead == -1) { + throw std::runtime_error("Read error: " + std::string(strerror(errno))); + } + buf[bytesRead] = '\0'; // Завершающий символ +} + +void ConnMq::Write(const char *buf, size_t count) { + if (mq_send(mq, buf, count, 0) == -1) { + throw std::runtime_error("Write error: " + std::string(strerror(errno))); + } +} + +ConnMq::~ConnMq() { + if (mq_close(mq) == -1) { + std::cerr << "Failed to close message queue: " << strerror(errno) << std::endl; + } + + if (create) { + if (mq_unlink(queueName.c_str()) == -1) { + std::cerr << "Failed to unlink message queue: " << strerror(errno) << std::endl; + } + } +} diff --git a/Umnov.Sergei/lab_02/src/connections/conn_mq.hpp b/Umnov.Sergei/lab_02/src/connections/conn_mq.hpp new file mode 100644 index 0000000..611018d --- /dev/null +++ b/Umnov.Sergei/lab_02/src/connections/conn_mq.hpp @@ -0,0 +1,22 @@ +#ifndef CONN_MQ_HPP +#define CONN_MQ_HPP + +#include +#include +#include + +class ConnMq { +public: + ConnMq(int id, bool create); + void Read(char *buf, size_t count); + void Write(const char *buf, size_t count); + ~ConnMq(); + +private: + int id; + bool create; + mqd_t mq; + std::string queueName; +}; + +#endif // CONN_MQ_HPP diff --git a/Umnov.Sergei/lab_02/src/connections/conn_seg.cpp b/Umnov.Sergei/lab_02/src/connections/conn_seg.cpp new file mode 100644 index 0000000..ff2d927 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/connections/conn_seg.cpp @@ -0,0 +1,49 @@ +#include "conn_seg.hpp" +#include +#include +#include + +ConnSeg::ConnSeg(int id, bool create, size_t size) : id(id), create(create), size(size) { + if (create) { + shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0666); + if (shmid == -1) { + throw std::runtime_error("Failed to create shared memory: " + std::string(strerror(errno))); + } + } else { + shmid = shmget(id, size, 0666); + if (shmid == -1) { + throw std::runtime_error("Failed to access shared memory: " + std::string(strerror(errno))); + } + } + + shmaddr = shmat(shmid, nullptr, 0); + if (shmaddr == (void *)-1) { + throw std::runtime_error("Failed to attach shared memory: " + std::string(strerror(errno))); + } +} + +ConnSeg::~ConnSeg() { + if (shmdt(shmaddr) == -1) { + std::cerr << "Failed to detach shared memory: " << strerror(errno) << std::endl; + } + + if (create) { + if (shmctl(shmid, IPC_RMID, nullptr) == -1) { + std::cerr << "Failed to remove shared memory: " << strerror(errno) << std::endl; + } + } +} + +void ConnSeg::Read(void *buf, size_t count) { + if (count > size) { + throw std::out_of_range("Read size exceeds shared memory segment size"); + } + memcpy(buf, shmaddr, count); +} + +void ConnSeg::Write(const void *buf, size_t count) { + if (count > size) { + throw std::out_of_range("Write size exceeds shared memory segment size"); + } + memcpy(shmaddr, buf, count); +} diff --git a/Umnov.Sergei/lab_02/src/connections/conn_seg.hpp b/Umnov.Sergei/lab_02/src/connections/conn_seg.hpp new file mode 100644 index 0000000..c455d63 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/connections/conn_seg.hpp @@ -0,0 +1,24 @@ +#ifndef CONN_SEG_HPP +#define CONN_SEG_HPP + +#include +#include +#include +#include + +class ConnSeg { +public: + ConnSeg(int id, bool create, size_t size = 1024); + ~ConnSeg(); + void Read(void *buf, size_t count); + void Write(const void *buf, size_t count); + +private: + int id; + bool create; + int shmid; + size_t size; + void *shmaddr; +}; + +#endif // CONN_SEG_HPP diff --git a/Umnov.Sergei/lab_02/src/host/host_fifo.cpp b/Umnov.Sergei/lab_02/src/host/host_fifo.cpp new file mode 100644 index 0000000..91e42d2 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/host/host_fifo.cpp @@ -0,0 +1,41 @@ +#include "conn_fifo.hpp" +#include +#include +#include +#include + +int main() { + try { + ConnFifo conn(1, true); // Инициализация FIFO как хоста + std::cout << "[FIFO Host] Initialized and running..." << std::endl; + + while (true) { + char buffer[1024] = {0}; + + // Чтение сообщений из FIFO + conn.Read(buffer, sizeof(buffer)); + if (strlen(buffer) > 0) { + std::cout << "[FIFO Host] Received: " << buffer << std::endl; + + // Если получено сообщение "exit", завершаем программу + if (std::string(buffer) == "exit") { + std::cout << "[FIFO Host] Client requested termination." << std::endl; + break; + } + + // Эхо-ответ клиенту + std::string response = "Echo from FIFO Host: " + std::string(buffer); + conn.Write(response.c_str(), response.size() + 1); + } + + // Небольшая пауза + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } catch (const std::exception &e) { + std::cerr << "[FIFO Host] Error: " << e.what() << std::endl; + return 1; + } + + std::cout << "[FIFO Host] Shutting down..." << std::endl; + return 0; +} diff --git a/Umnov.Sergei/lab_02/src/host/host_gui.cpp b/Umnov.Sergei/lab_02/src/host/host_gui.cpp new file mode 100644 index 0000000..1ea4a1d --- /dev/null +++ b/Umnov.Sergei/lab_02/src/host/host_gui.cpp @@ -0,0 +1,67 @@ +#include "host_gui.hpp" +#include +#include + +HostGUI::HostGUI(QWidget *parent) + : QMainWindow(parent) + , clientSegConn(1, true) + , clientMqConn(1, true) + , clientFifoConn(1, true) + , activityTimer(new QTimer(this)) { + + centralWidget = new QWidget(this); + layout = new QVBoxLayout(centralWidget); + + chatDisplay = new QTextEdit(centralWidget); + messageInput = new QLineEdit(centralWidget); + sendButton = new QPushButton("Send", centralWidget); + + layout->addWidget(chatDisplay); + layout->addWidget(messageInput); + layout->addWidget(sendButton); + + setCentralWidget(centralWidget); + + connect(sendButton, &QPushButton::clicked, this, &HostGUI::onSendButtonClicked); + connect(activityTimer, &QTimer::timeout, this, &HostGUI::checkActivity); + + activityTimer->start(60000); // Таймер на 1 минуту +} + +HostGUI::~HostGUI() { + delete layout; + delete centralWidget; +} + +void HostGUI::onSendButtonClicked() { + QString message = messageInput->text(); + if (!message.isEmpty()) { + sendMessage(message); + messageInput->clear(); + activityTimer->start(60000); // Перезапуск таймера + } +} + +void HostGUI::sendMessage(const QString &message) { + QByteArray messageData = message.toUtf8(); + clientSegConn.Write(messageData.constData(), messageData.size()); + clientMqConn.Write(messageData.constData(), messageData.size()); + clientFifoConn.Write(messageData.constData(), messageData.size()); +} + +void HostGUI::receiveMessage() { + char buffer[1024]; + clientSegConn.Read(buffer, sizeof(buffer)); + chatDisplay->append(QString::fromUtf8(buffer)); + + clientMqConn.Read(buffer, sizeof(buffer)); + chatDisplay->append(QString::fromUtf8(buffer)); + + clientFifoConn.Read(buffer, sizeof(buffer)); + chatDisplay->append(QString::fromUtf8(buffer)); +} + +void HostGUI::checkActivity() { + QMessageBox::warning(this, "Inactivity", "No messages sent in the last minute. Terminating client."); + QApplication::quit(); +} diff --git a/Umnov.Sergei/lab_02/src/host/host_gui.hpp b/Umnov.Sergei/lab_02/src/host/host_gui.hpp new file mode 100644 index 0000000..f06c755 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/host/host_gui.hpp @@ -0,0 +1,40 @@ +#ifndef HOST_GUI_HPP +#define HOST_GUI_HPP + +#include +#include +#include +#include +#include +#include +#include "conn_seg.hpp" +#include "conn_mq.hpp" +#include "conn_fifo.hpp" + +class HostGUI : public QMainWindow { + Q_OBJECT + +public: + HostGUI(QWidget *parent = nullptr); + ~HostGUI(); + +public slots: + void onSendButtonClicked(); + void checkActivity(); + +private: + QTextEdit *chatDisplay; + QLineEdit *messageInput; + QPushButton *sendButton; + QVBoxLayout *layout; + QWidget *centralWidget; + ConnSeg clientSegConn; + ConnMq clientMqConn; + ConnFifo clientFifoConn; + QTimer *activityTimer; + + void sendMessage(const QString &message); + void receiveMessage(); +}; + +#endif // HOST_GUI_HPP diff --git a/Umnov.Sergei/lab_02/src/host/host_mq.cpp b/Umnov.Sergei/lab_02/src/host/host_mq.cpp new file mode 100644 index 0000000..32f6bf7 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/host/host_mq.cpp @@ -0,0 +1,41 @@ +#include "conn_mq.hpp" +#include +#include +#include +#include + +int main() { + try { + ConnMq conn(1, true); // Инициализация очереди сообщений как хоста + std::cout << "[MQ Host] Initialized and running..." << std::endl; + + while (true) { + char buffer[1024] = {0}; + + // Чтение сообщений из очереди сообщений + conn.Read(buffer, sizeof(buffer)); + if (strlen(buffer) > 0) { + std::cout << "[MQ Host] Received: " << buffer << std::endl; + + // Если получено сообщение "exit", завершаем программу + if (std::string(buffer) == "exit") { + std::cout << "[MQ Host] Client requested termination." << std::endl; + break; + } + + // Эхо-ответ клиенту + std::string response = "Echo from MQ Host: " + std::string(buffer); + conn.Write(response.c_str(), response.size() + 1); + } + + // Небольшая пауза + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } catch (const std::exception &e) { + std::cerr << "[MQ Host] Error: " << e.what() << std::endl; + return 1; + } + + std::cout << "[MQ Host] Shutting down..." << std::endl; + return 0; +} diff --git a/Umnov.Sergei/lab_02/src/host/host_seg.cpp b/Umnov.Sergei/lab_02/src/host/host_seg.cpp new file mode 100644 index 0000000..e97f739 --- /dev/null +++ b/Umnov.Sergei/lab_02/src/host/host_seg.cpp @@ -0,0 +1,41 @@ +#include "conn_seg.hpp" +#include +#include +#include +#include + +int main() { + try { + ConnSeg conn(1, true); // Инициализация сегмента разделяемой памяти как хоста + std::cout << "[SHM Host] Initialized and running..." << std::endl; + + while (true) { + char buffer[1024] = {0}; + + // Чтение сообщений из разделяемой памяти + conn.Read(buffer, sizeof(buffer)); + if (strlen(buffer) > 0) { + std::cout << "[SHM Host] Received: " << buffer << std::endl; + + // Если получено сообщение "exit", завершаем программу + if (std::string(buffer) == "exit") { + std::cout << "[SHM Host] Client requested termination." << std::endl; + break; + } + + // Эхо-ответ клиенту + std::string response = "Echo from SHM Host: " + std::string(buffer); + conn.Write(response.c_str(), response.size() + 1); + } + + // Небольшая пауза + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } catch (const std::exception &e) { + std::cerr << "[SHM Host] Error: " << e.what() << std::endl; + return 1; + } + + std::cout << "[SHM Host] Shutting down..." << std::endl; + return 0; +}