diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d4b15b..7914164 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(maze LANGUAGES CXX) set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++23") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++23 -Wall") include_directories( include diff --git a/include/client.hpp b/include/client.hpp index a70d040..50c8cc2 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -1,20 +1,22 @@ -#ifndef CLIENT -#define CLIENT +#ifndef CLIENT_HPP +#define CLIENT_HPP #include #include #include #include #include - -const int PORT = 8080; +#include class Client{ private: int sock; public: - Client() : sock(0){}; - void run(); + Client(); + + void run(const std::string&, const unsigned short); + void game(); + int ping(struct sockaddr_in); }; diff --git a/include/maze.hpp b/include/maze.hpp index 3c14a1d..2c21bd9 100644 --- a/include/maze.hpp +++ b/include/maze.hpp @@ -11,28 +11,24 @@ const int MAZE_SIZE = 9; const int DIRECTIONS = 4; const int MIN_WALLS = 3; const int MAX_WALLS = 5; -const int DEFAULT_MOVES = 10; class Maze{ - private: - std::unordered_map> graph; - int moves_left; - bool is_path_exists(int, int); +private: + std::unordered_map> graph; + int moves_left; + bool is_path_exists(int start, int end); - struct Edge { - int node1, dir1; - int node2, dir2; - }; - public: - Maze(bool); - bool test_mode; - int get_moves_left() const; - bool is_wall(int, int) const; + struct Edge { + int node1, dir1; + int node2, dir2; + }; +public: + bool test_mode; - void set_moves_left(int); - - //void generate_maze(); - //void print_maze_info(); - //void play_game(); + Maze(bool flag, int steps); + int get_moves_left() const; + bool is_wall(int node, int direction) const; + + void set_moves_left(int _steps); }; #endif diff --git a/include/server.hpp b/include/server.hpp index af190d0..cad8636 100644 --- a/include/server.hpp +++ b/include/server.hpp @@ -7,20 +7,23 @@ #include #include #include +#include #include #include -const int PORT = 8080; -const int MAX_CLIENTS = 100; +const int MAX_CLIENTS = 512; +const int BUFFER_SIZE = 1024; class Server { private: bool service_mode; - void handle_client(int client_socket, bool _mode); // Принимает клиентский сокет + int server_socket; + + void handle_client(int socket, bool flag, int steps); bool check_status(Maze& maze); public: - Server() : service_mode(false){}; - void start(); // Запуск сервера + Server(const std::string& host, const unsigned short port, bool service_flag); + void start(int steps = 10); }; #endif \ No newline at end of file diff --git a/src/client/client.cpp b/src/client/client.cpp index 77abbed..4ccada0 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1,52 +1,60 @@ #include "client.hpp" -void print_instructions() { - std::cout << "Доступные команды:\n"; - std::cout << " - вперёд\n"; - std::cout << " - направо\n"; - std::cout << " - налево\n"; - std::cout << " - назад\n"; - std::cout << " - сдаюсь\n"; - std::cout << "Введите команду для хода.\n"; -} +// void print_instructions() { +// std::cout << "Доступные команды:" << std::endl; +// std::cout << " - вперёд" << std::endl; +// std::cout << " - направо" << std::endl; +// std::cout << " - налево" << std::endl; +// std::cout << " - назад" << std::endl; +// std::cout << " - сдаюсь" << std::endl; +// std::cout << "Введите команду для хода" << std::endl; +// } int Client::ping(struct sockaddr_in address){ - return connect(sock, (struct sockaddr*)&address, sizeof(address)) > 0; + return connect(sock, (struct sockaddr*)&address, sizeof(address)) != 0; } -void Client::run() { - struct sockaddr_in serv_addr; - +Client::Client(){ // Создание сокета if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - throw std::runtime_error("[Client::request] connect(2) call error"); + throw std::runtime_error("Error in socket create"); } +} + +void Client::run(const std::string& h, const unsigned short p) { + struct sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(PORT); - // Преобразование IP-адреса из текстового вида в бинарный - if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { - throw std::runtime_error("[Client::request] connect(2) call error"); + hostent* host_name; + host_name = gethostbyname(h.c_str()); // Преобразование названия хоста в IP-адрес. + if (host_name == nullptr) { + throw std::runtime_error("Error in get hostname"); } + + serv_addr.sin_port = htons(p); + memcpy(&serv_addr.sin_addr.s_addr, host_name->h_addr, host_name->h_length); // Подключение к серверу if (ping(serv_addr)) { - throw std::runtime_error("Connection lost!"); + throw std::runtime_error("Invalid hostname:port"); } std::cout << "Подключено к серверу. Введите ваше имя: "; std::string player_name; std::getline(std::cin, player_name); - if (ping(serv_addr)) { + if (!ping(serv_addr)) { throw std::runtime_error("Connection lost!"); } + // Отправка имени игрока на сервер send(sock, player_name.c_str(), player_name.size(), 0); - std::cout << "Игра началась!\n"; +} - print_instructions(); +void Client::game(){ + std::cout << "Игра началась!" << std::endl; + //print_instructions(); char buffer[1024] = {0}; while (true) { @@ -74,6 +82,5 @@ void Client::run() { break; } } - close(sock); } \ No newline at end of file diff --git a/src/client/client_main.cpp b/src/client/client_main.cpp index 15b6c27..6ecf37f 100644 --- a/src/client/client_main.cpp +++ b/src/client/client_main.cpp @@ -1,9 +1,27 @@ #include "client.hpp" -int main(){ +int main(int argc, char** argv){ + int opt; + std::string host = "localhost"; + short unsigned port = 1024u; + + while ((opt = getopt(argc, argv, "h:p:")) != -1) { + switch (opt) { + case 'h': + host = optarg; + break; + case 'p': + port = static_cast(atoi(optarg)); + break; + default: + break; + } + } + try { Client client; - client.run(); + client.run(host, port); + client.game(); } catch (const std::runtime_error& e){ std::cerr << "Client application error: " << e.what() << std::endl; return 1; diff --git a/src/server/maze.cpp b/src/server/maze.cpp index 7225f6c..1ac2db1 100644 --- a/src/server/maze.cpp +++ b/src/server/maze.cpp @@ -1,14 +1,14 @@ #include "maze.hpp" #include -Maze::Maze(bool _test_mode){ +Maze::Maze(bool _test_mode, int _steps){ std::vector edges = { {0, 1, 1, 3}, {0, 0, 3, 2}, {1, 1, 2, 3}, {1, 0, 4, 2}, {2, 0, 5, 2}, {3, 1, 4, 3}, {3, 0, 6, 2}, {4, 1, 5, 3}, {4, 0, 7, 2}, {5, 0, 8, 2}, {6, 1, 7, 3}, {7, 1, 8, 3} }; test_mode = _test_mode; - moves_left = test_mode ? INT_MAX : DEFAULT_MOVES; + moves_left = test_mode ? INT_MAX : _steps; for (int i = 0; i < MAZE_SIZE; ++i) { graph[i] = std::vector(DIRECTIONS, true); diff --git a/src/server/server.cpp b/src/server/server.cpp index 668a6e3..bd7074d 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -4,24 +4,51 @@ bool Server::check_status(Maze &maze) { return (!maze.test_mode && maze.get_moves_left() > 0); } -void Server::handle_client(int client_socket, bool mode) { - Maze maze(mode); // Создаем экземпляр лабиринта для клиента - int current_position = 0; // Начальная позиция игрока +Server::Server(const std::string& h, const unsigned short p, bool _service){ + service_mode = _service; + if (service_mode) { + std::cout << "Service mode is ON" << std::endl; + } + + sockaddr_in server_address; + + if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + throw std::runtime_error("Error in create socket"); + } + + memset(reinterpret_cast(&server_address), '\0', sizeof(server_address)); + server_address.sin_family = AF_INET; + hostent* host_name; + host_name = gethostbyname(h.c_str()); // Преобразование названия хоста в IP-адрес. + if (host_name == nullptr) { + throw std::runtime_error("Error in getting hostname"); + } + + server_address.sin_port = htons(p); + memcpy(&server_address.sin_addr.s_addr, host_name->h_addr, host_name->h_length); + if (bind(server_socket, reinterpret_cast(&server_address), sizeof(server_address)) != 0) { + throw std::runtime_error("Error in bind part"); + } + std::cout << "Сервер запущен на хосте " << h << " на порту " << p << std::endl; +} + +void Server::handle_client(int client_socket, bool mode, int steps) { + Maze maze(mode, steps); + int current_position = 0; std::string player_name; - char buffer[1024] = {0}; + char buffer[BUFFER_SIZE] = {0}; std::string response; - // Получение имени игрока int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0); if (bytes_received <= 0) { - std::cerr << "Ошибка получения имени игрока.\n"; + std::cout << "Error in getting player name"; close(client_socket); return; } player_name = std::string(buffer); - std::cout << "Новый игрок: " << player_name << "\n"; + std::cout << "Новый игрок: " << player_name << std::endl; while (true) { int moves_left = maze.get_moves_left(); @@ -33,7 +60,7 @@ void Server::handle_client(int client_socket, bool mode) { } std::string command(buffer); - std::cout << "Получена команда от игрока " << player_name << ": " << command << "\n"; + std::cout << "Получена команда от игрока " << player_name << ": " << command << std::endl; int direction = -1; int new_position = current_position; @@ -86,10 +113,13 @@ void Server::handle_client(int client_socket, bool mode) { break; } + maze.set_moves_left(moves_left - 1); + if (!check_status(maze)) + break; + int x = current_position % 3; int y = current_position / 3; std::string text("(" + std::to_string(x) + ", " + std::to_string(y) + ")\n"); - maze.set_moves_left(moves_left - 1); response = "успешно, осталось " + std::to_string(maze.get_moves_left()) + " ходов. Вы находитесь в " + text; send(client_socket, response.c_str(), response.size(), 0); } @@ -101,48 +131,24 @@ void Server::handle_client(int client_socket, bool mode) { } close(client_socket); - std::cout << "Игрок " << player_name << " отключился.\n"; + std::cout << "Игрок " << player_name << " отключился" << std::endl; } -void Server::start() { - int server_fd, new_socket; - struct sockaddr_in address; - int opt = 1; - int addrlen = sizeof(address); +void Server::start(int steps) { + int new_socket; - if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { - perror("Ошибка создания сокета"); - exit(EXIT_FAILURE); + if (listen(server_socket, MAX_CLIENTS) < 0) { + throw std::runtime_error("Error in listen"); } - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { - perror("Ошибка настройки сокета"); - exit(EXIT_FAILURE); - } - - address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons(PORT); - - if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) { - perror("Ошибка привязки сокета"); - exit(EXIT_FAILURE); - } - - if (listen(server_fd, MAX_CLIENTS) < 0) { - perror("Ошибка прослушивания"); - exit(EXIT_FAILURE); - } - - std::cout << "Сервер запущен на порту " << PORT << "\n"; - + sockaddr address; + socklen_t address_size = sizeof(address); while (true) { - if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) { - perror("Ошибка принятия соединения"); - exit(EXIT_FAILURE); + if ((new_socket = accept(server_socket, (struct sockaddr*)&address, &address_size)) < 0) { + throw std::runtime_error("Error in accept"); } - std::cout << "Новое соединение установлено.\n"; - std::thread(&Server::handle_client, this, new_socket, true).detach(); + std::cout << "Новое соединение установлено" << std::endl; + std::thread(&Server::handle_client, this, new_socket, service_mode, steps).detach(); } } \ No newline at end of file diff --git a/src/server/server_main.cpp b/src/server/server_main.cpp index 15946c9..e751b97 100644 --- a/src/server/server_main.cpp +++ b/src/server/server_main.cpp @@ -1,9 +1,46 @@ #include "server.hpp" int main(int argc, char **argv) { - - Server server; - server.start(); + int opt; + std::string host = "localhost"; + int steps = 10; + bool service_mode = false; + short unsigned port = 1024u; + while ((opt = getopt(argc, argv, "h:p:sn:")) != -1) { + switch (opt) { + case 'h': + host = optarg; + break; + case 'p': + port = static_cast(atoi(optarg)); + break; + case 'n': + steps = atoi(optarg); + if(steps <= 0) { + std::cerr << "Invalid steps" << std::endl; + return 1; + } + break; + case 's': + service_mode = true; + break; + default: + break; + } + } + + try { + Server server(host, port, service_mode); + server.start(steps); + } catch (const std::runtime_error& e){ + std::cerr << "Server application error: " << e.what() << std::endl; + return 1; + } catch (...){ + std::cerr << "Unexpected error in client application" << std::endl; + return 2; + } + + std::cout << "Server application finished" << std::endl; return 0; } \ No newline at end of file