diff --git a/01_Client/.gitignore b/01_Client/.gitignore new file mode 100644 index 0000000..ba2906d --- /dev/null +++ b/01_Client/.gitignore @@ -0,0 +1 @@ +main diff --git a/01_Client/include/Client.h b/01_Client/include/Client.h new file mode 100644 index 0000000..32619c7 --- /dev/null +++ b/01_Client/include/Client.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include +#include "Network.h" +#include "SimpleChecker.h" + +typedef uint64_t calc_t; +typedef uint64_t count_t; + +class Client +{ +private: + typedef uint64_t code_t; + + static const code_t CODE_GET_MAX_SIMPLE = 1; + static const code_t CODE_GET_LAST_N = 2; + static const code_t CODE_CALCULATE = 3; + + Network _network; + +public: + Client(std::string host_name, uint16_t port); + + calc_t get_max_prime() const; + std::vector get_last_n(count_t n) const; + void calculate(count_t n) const; +}; \ No newline at end of file diff --git a/01_Client/include/Network.h b/01_Client/include/Network.h new file mode 100644 index 0000000..cb6f5dc --- /dev/null +++ b/01_Client/include/Network.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +struct NetworkException +{ +private: + std::string message; + +public: + NetworkException(std::string message) + : message(message) + { + } + + std::string get_message() const + { + return message; + } +}; + +class Network +{ +private: + int _sockfd; + +public: + Network(std::string host_name, uint16_t port); + + void send_int(uint64_t x, size_t size) const; + uint64_t read_int(size_t size) const; + + void send_vector(const std::vector &v, size_t size_length, size_t size_num) const; + std::vector read_vector(size_t size_length, size_t size_num) const; +}; \ No newline at end of file diff --git a/01_Client/include/SimpleChecker.h b/01_Client/include/SimpleChecker.h new file mode 100644 index 0000000..4e68242 --- /dev/null +++ b/01_Client/include/SimpleChecker.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include + +class SimpleChecker +{ +public: + SimpleChecker() = delete; + + static bool is_prime(uint64_t n); + static std::vector check_interval(uint64_t start_num, size_t n); +}; \ No newline at end of file diff --git a/01_Client/src/Client.cpp b/01_Client/src/Client.cpp new file mode 100644 index 0000000..374d75f --- /dev/null +++ b/01_Client/src/Client.cpp @@ -0,0 +1,38 @@ +#include "Client.h" + +using std::string; +using std::vector; + +Client::Client(string host_name, uint16_t port) +: _network(host_name, port) +{ +} + +calc_t Client::get_max_prime() const +{ + _network.send_int(CODE_GET_MAX_SIMPLE, sizeof(CODE_GET_MAX_SIMPLE)); + return (calc_t)_network.read_int(sizeof(calc_t)); +} + +vector Client::get_last_n(count_t n) const +{ + _network.send_int(CODE_GET_LAST_N, sizeof(CODE_GET_LAST_N)); + _network.send_int(n, sizeof(n)); + + vector res; + vector response = _network.read_vector(sizeof(count_t), sizeof(calc_t)); + for (uint64_t x : response) + res.push_back((calc_t)x); + return res; +} + +void Client::calculate(count_t n) const +{ + _network.send_int(CODE_CALCULATE, sizeof(CODE_CALCULATE)); + _network.send_int(n, sizeof(n)); + + calc_t start_num = (calc_t)_network.read_int(sizeof(calc_t)); + vector prime_nums = SimpleChecker::check_interval(start_num, n); + + _network.send_vector(prime_nums, sizeof(count_t), sizeof(calc_t)); +} \ No newline at end of file diff --git a/01_Client/src/Network.cpp b/01_Client/src/Network.cpp new file mode 100644 index 0000000..4bf7757 --- /dev/null +++ b/01_Client/src/Network.cpp @@ -0,0 +1,64 @@ +#include "Network.h" + +using std::vector; +using std::string; + +Network::Network(string host_name, uint16_t port) +{ + _sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (_sockfd < 0) { + throw NetworkException("Could not open socket"); + } + + struct hostent *server = gethostbyname(host_name.c_str()); + + if (server == NULL) { + throw NetworkException("Could not find host"); + } + + struct sockaddr_in serv_addr; + memset((char*)&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + bcopy(server->h_addr, (char*) &serv_addr.sin_addr.s_addr, (size_t) server->h_length); + serv_addr.sin_port = htons(port); + + if (connect(_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + throw NetworkException("Could not connect to server"); + } +} + +void Network::send_int(uint64_t x, size_t size) const +{ + if (write(_sockfd, (char*)&x, size) < 0) { + throw NetworkException("Could not send number"); + } +} + +uint64_t Network::read_int(size_t size) const +{ + uint64_t x = 0; + if (read(_sockfd, (char*)&x, size) < 0) { + throw NetworkException("Could not read number"); + } + return x; +} + +void Network::send_vector(const vector &v, size_t size_length, size_t size_num) const +{ + send_int(v.size(), size_length); + for (uint64_t x : v) { + send_int(x, size_num); + } +} + +vector Network::read_vector(size_t size_length, size_t size_num) const +{ + vector v; + + size_t n = read_int(size_length); + for (size_t i = 0; i < n; i++) { + v.push_back(read_int(size_num)); + } + + return v; +} \ No newline at end of file diff --git a/01_Client/src/SimpleChecker.cpp b/01_Client/src/SimpleChecker.cpp new file mode 100644 index 0000000..c351580 --- /dev/null +++ b/01_Client/src/SimpleChecker.cpp @@ -0,0 +1,27 @@ +#include "SimpleChecker.h" + +using std::vector; + +bool SimpleChecker::is_prime(uint64_t n) +{ + if (n < 2) + return false; + + for (uint64_t d = 2; d*d <= n; d++) + if ((n / d) * d == n) + return false; + return true; +} + +vector SimpleChecker::check_interval(uint64_t start_num, size_t n) +{ + vector res; + + for (size_t dx = 0; dx < n; dx++) { + size_t x = start_num + dx; + if (is_prime(x)) + res.push_back(x); + } + + return res; +} \ No newline at end of file diff --git a/01_Client/src/main.cpp b/01_Client/src/main.cpp new file mode 100644 index 0000000..bcb7ca3 --- /dev/null +++ b/01_Client/src/main.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include "Client.h" + +using namespace std; + +tuple read_addres() +{ + string host_name; + uint16_t port; + + cout << "Enter host name and port" << endl; + cin >> host_name >> port; + + return make_tuple(host_name, port); +} + +void print_commands() +{ + cout << endl; + cout << "List of commands:" << endl; + cout << "1. get_max_prime" << endl; + cout << "2. get_last_n " << endl; + cout << "3. calculate " << endl; + cout << "4. exit" << endl; + cout << endl; +} + +string read_command() +{ + cout << endl; + cout << "Enter command" << endl; + string command; + cin >> command; + return command; +} + +int main() +{ + try { + string host_name; + uint16_t port; + tie(host_name, port) = read_addres(); + Client client(host_name, port); + + print_commands(); + + while (true) + { + string command = read_command(); + if (command == "get_max_prime") { + calc_t x = client.get_max_prime(); + cout << x << endl; + } else if (command == "get_last_n") { + count_t n; + cin >> n; + vector v = client.get_last_n(n); + for (calc_t x : v) + cout << x << " "; + cout << endl; + } else if (command == "calculate") { + count_t n; + cin >> n; + client.calculate(n); + cout << "Calculations completed" << endl; + } else if (command == "exit") { + break; + } else { + cout << "This is an unknown command" << endl; + } + } + } catch (NetworkException &e) { + cout << e.get_message() << endl; + } + + return 0; +} \ No newline at end of file diff --git a/02_Server/.gitignore b/02_Server/.gitignore new file mode 100644 index 0000000..ba2906d --- /dev/null +++ b/02_Server/.gitignore @@ -0,0 +1 @@ +main diff --git a/02_Server/include/Calculator.h b/02_Server/include/Calculator.h new file mode 100644 index 0000000..b8bdf27 --- /dev/null +++ b/02_Server/include/Calculator.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +class Calculator +{ +public: + Calculator() = delete; + + static double get_sum(double a, double b); + static double get_diff(double a, double b); + static double get_mul(double a, double b); + static double get_quot(double a, double b); + static uint64_t get_fact(uint64_t a); + static double get_sqrt(double a); +}; \ No newline at end of file diff --git a/02_Server/include/Server.h b/02_Server/include/Server.h new file mode 100644 index 0000000..37db3d0 --- /dev/null +++ b/02_Server/include/Server.h @@ -0,0 +1,187 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include "Calculator.h" + +struct NetworkException +{ +private: + std::string message; + +public: + NetworkException(std::string message) + : message(message) + { + } + + std::string get_message() const + { + return message; + } +}; + +class Server +{ +private: + int _sockfd; + + void init_network(uint16_t port); + int accept_client(); + +public: + typedef uint64_t code_t; + typedef uint64_t uint_t; + typedef double float_t; + + static const code_t CODE_FAST = 1; + static const code_t CODE_LONG_ID = 2; + static const code_t CODE_LONG = 3; + + static const code_t CODE_GET_SUM = 1; + static const code_t CODE_GET_DIFF = 2; + static const code_t CODE_GET_MUL = 3; + static const code_t CODE_GET_QUOT = 4; + static const code_t CODE_GET_FACT = 5; + static const code_t CODE_GET_SQRT = 6; + + Server(uint16_t port); + ~Server(); + + static void read_message(int sockfd, char* x, size_t size); + static void send_message(int sockfd, char* x, size_t size); + + void run(); +}; + +struct TaskData +{ +private: + bool is_long_operation; + bool finished; + + void init_state() + { + finished = false; + mutex_is_finished = new pthread_mutex_t; + pthread_mutex_init(mutex_is_finished, NULL); + } + +public: + pthread_t *thread; + int sockfd; + + Server::code_t command_type; + Server::uint_t id; + char* param = NULL; + + pthread_mutex_t *mutex_sockfd; + pthread_mutex_t *mutex_is_finished; + + TaskData(pthread_t *thread, int sockfd) + : thread(thread), sockfd(sockfd) + { + is_long_operation = false; + + init_state(); + + mutex_sockfd = new pthread_mutex_t; + pthread_mutex_init(mutex_sockfd, NULL); + } + + TaskData(TaskData &other, pthread_t *thread, Server::code_t command_type, Server::uint_t id, char* param) + : thread(thread), command_type(command_type), id(id), param(param) + { + is_long_operation = true; + + init_state(); + + sockfd = other.sockfd; + mutex_sockfd = other.mutex_sockfd; + } + + ~TaskData() + { + pthread_join(*thread, NULL); + + if (param != NULL) { + delete[] param; + } + free(thread); + + pthread_mutex_destroy(mutex_is_finished); + + if (!is_long_operation) { + close(sockfd); + pthread_mutex_destroy(mutex_sockfd); + } + } + + void mark_finished() + { + pthread_mutex_lock(mutex_is_finished); + finished = true; + pthread_mutex_unlock(mutex_is_finished); + } + + bool is_finished() + { + pthread_mutex_lock(mutex_is_finished); + bool ans = finished; + pthread_mutex_unlock(mutex_is_finished); + return ans; + } +}; + +class TaskController +{ +private: + std::vector tasks; + +public: + TaskController() + {} + + void add(TaskData *task) + { + tasks.push_back(task); + } + + void tryFinish() + { + std::vector remaining_tasks; + for (TaskData *task : tasks) + { + if (task->is_finished()) + { + delete task; + } else { + remaining_tasks.push_back(task); + } + } + + tasks = remaining_tasks; + } + + void finish() + { + while (tasks.size() > 0) { + tryFinish(); + } + } +}; \ No newline at end of file diff --git a/02_Server/src/Calculator.cpp b/02_Server/src/Calculator.cpp new file mode 100644 index 0000000..d10107d --- /dev/null +++ b/02_Server/src/Calculator.cpp @@ -0,0 +1,35 @@ +#include "Calculator.h" + +double Calculator::get_sum(double a, double b) +{ + return a + b; +} + +double Calculator::get_diff(double a, double b) +{ + return a - b; +} + +double Calculator::get_mul(double a, double b) +{ + return a * b; +} + +double Calculator::get_quot(double a, double b) +{ + return a / b; +} + +uint64_t Calculator::get_fact(uint64_t a) +{ + uint64_t res = 1; + for (uint64_t i = 1; i <= a; i++) { + res *= i; + } + return res; +} + +double Calculator::get_sqrt(double a) +{ + return sqrt(a); +} \ No newline at end of file diff --git a/02_Server/src/Server.cpp b/02_Server/src/Server.cpp new file mode 100644 index 0000000..67544ce --- /dev/null +++ b/02_Server/src/Server.cpp @@ -0,0 +1,211 @@ +#include "Server.h" + +void Server::init_network(uint16_t port) +{ + _sockfd = socket(AF_INET, SOCK_STREAM, 0); + + if (_sockfd < 0) { + throw NetworkException("Could not open socket"); + } + + struct sockaddr_in serv_addr; + + bzero((char *) &serv_addr, sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(port); + + if (bind(_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + throw NetworkException("Could not bind"); + } +} + +Server::Server(uint16_t port) +{ + init_network(port); +} + +int Server::accept_client() +{ + int sockfd; + unsigned int clilen; + struct sockaddr_in cli_addr; + + listen(_sockfd, 5); + clilen = sizeof(cli_addr); + + sockfd = accept(_sockfd, (struct sockaddr *) &cli_addr, &clilen); + + if (sockfd < 0) { + throw NetworkException("Could not accept"); + } + + return sockfd; +} + +void Server::send_message(int sockfd, char* x, size_t size) +{ + if (write(sockfd, x, size) <= 0) { + throw NetworkException("Could not write message"); + } +} + +void Server::read_message(int sockfd, char* x, size_t size) +{ + if (read(sockfd, x, size) <= 0) { + throw NetworkException("Could not read message"); + } +} + +void* long_operation(void *void_params) +{ + TaskData *task_data = (TaskData*)void_params; + int sockfd = task_data->sockfd; + + Server::code_t command_type = task_data->command_type; + + try { + pthread_mutex_lock(task_data->mutex_sockfd); + Server::uint_t code = Server::CODE_LONG_ID; + Server::send_message(sockfd, (char*)&code, sizeof(code)); + Server::send_message(sockfd, (char*)(&(task_data->id)), sizeof(task_data->id)); + pthread_mutex_unlock(task_data->mutex_sockfd); + + Server::uint_t tmp_uint; + Server::float_t tmp_float; + char* res_buff = NULL; + size_t res_size; + switch(command_type) { + case Server::CODE_GET_FACT: + tmp_uint = *((Server::uint_t*)(task_data->param)); + tmp_uint = Calculator::get_fact(tmp_uint); + res_buff = (char*)&tmp_uint; + res_size = sizeof(tmp_uint); + break; + + case Server::CODE_GET_SQRT: + tmp_float = *((Server::float_t*)(task_data->param)); + tmp_float = Calculator::get_sqrt(tmp_float); + res_buff = (char*)&tmp_float; + res_size = sizeof(tmp_float); + break; + } + + pthread_mutex_lock(task_data->mutex_sockfd); + code = Server::CODE_LONG; + Server::send_message(sockfd, (char*)&code, sizeof(code)); + Server::send_message(sockfd, (char*)(&(task_data->id)), sizeof(task_data->id)); + Server::send_message(sockfd, res_buff, res_size); + pthread_mutex_unlock(task_data->mutex_sockfd); + } catch (NetworkException &e) { + pthread_mutex_unlock(task_data->mutex_sockfd); + } + + task_data->mark_finished(); +} + +void* client_service(void *void_params) +{ + TaskData *task_data = (TaskData*)void_params; + int sockfd = task_data->sockfd; + + TaskController task_controller; + Server::uint_t id = 1; + + while (true) { + try { + Server::code_t command_type; + Server::read_message(sockfd, (char*)&command_type, sizeof(command_type)); + + if (command_type == Server::CODE_GET_FACT || command_type == Server::CODE_GET_SQRT) { + char* buff; + if (command_type == Server::CODE_GET_FACT) { + buff = new char[sizeof(Server::uint_t)]; + Server::read_message(sockfd, buff, sizeof(Server::uint_t)); + } else { + buff = new char[sizeof(Server::float_t)]; + Server::read_message(sockfd, buff, sizeof(Server::float_t)); + } + + pthread_t *thread = (pthread_t*)malloc(sizeof(pthread_t)); + TaskData *long_task_data = new TaskData(*task_data, thread, command_type, id++, buff); + pthread_create(thread, NULL, long_operation, (void*)long_task_data); + + task_controller.add(long_task_data); + } else { + Server::float_t a, b, c; + Server::read_message(sockfd, (char*)&a, sizeof(a)); + Server::read_message(sockfd, (char*)&b, sizeof(b)); + + switch(command_type) { + case Server::CODE_GET_SUM: + c = Calculator::get_sum(a, b); + break; + + case Server::CODE_GET_DIFF: + c = Calculator::get_diff(a, b); + break; + + case Server::CODE_GET_MUL: + c = Calculator::get_mul(a, b); + break; + + case Server::CODE_GET_QUOT: + c = Calculator::get_quot(a, b); + break; + + default: + throw NetworkException("Unknown command"); + break; + } + + try { + pthread_mutex_lock(task_data->mutex_sockfd); + Server::uint_t code = Server::CODE_FAST; + Server::send_message(sockfd, (char*)&code, sizeof(code)); + Server::send_message(sockfd, (char*)&c, sizeof(c)); + pthread_mutex_unlock(task_data->mutex_sockfd); + } catch (NetworkException &e) { + pthread_mutex_unlock(task_data->mutex_sockfd); + throw e; + } + } + } catch (NetworkException &e) { + break; + } + + task_controller.tryFinish(); + } + + task_controller.finish(); + task_data->mark_finished(); +} + +void Server::run() +{ + TaskController task_controller; + + while (true) { + int sockfd; + try { + sockfd = accept_client(); + } catch (NetworkException &e) { + continue; + } + + pthread_t *thread = (pthread_t*)malloc(sizeof(pthread_t)); + TaskData *task_data = new TaskData(thread, sockfd); + pthread_create(thread, NULL, client_service, (void*)task_data); + + task_controller.add(task_data); + task_controller.tryFinish(); + } + + task_controller.finish(); +} + +Server::~Server() +{ + close(_sockfd); +} \ No newline at end of file diff --git a/02_Server/src/main.cpp b/02_Server/src/main.cpp new file mode 100644 index 0000000..0c2a9bb --- /dev/null +++ b/02_Server/src/main.cpp @@ -0,0 +1,28 @@ +#include +#include "Server.h" + +using namespace std; + +uint16_t read_port() +{ + uint16_t port; + + cout << "Enter port" << endl; + cin >> port >> port; + + return port; +} + +int main() +{ + try { + //uint16_t port = read_port(); + uint16_t port = 5001; + Server server(port); + server.run(); + } catch (...) { + cout << "AAAAAAAAAAAAAAA" << endl; + } + + return 0; +} \ No newline at end of file