diff --git a/03_UDP/.gitignore b/03_UDP/.gitignore new file mode 100644 index 0000000..ba2906d --- /dev/null +++ b/03_UDP/.gitignore @@ -0,0 +1 @@ +main diff --git a/03_UDP/include/Client.h b/03_UDP/include/Client.h new file mode 100644 index 0000000..857bc77 --- /dev/null +++ b/03_UDP/include/Client.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include +#include "Network.h" +#include "SimpleChecker.h" + +typedef uint64_t calc_t; + +class Client +{ +private: + static const calc_t CODE_GET_MAX_SIMPLE = 1; + static const calc_t CODE_GET_LAST_N = 2; + static const calc_t CODE_CALCULATE = 3; + static const calc_t CODE_SEND_CALCULATED = 4; + + Network _network; + +public: + Client(std::string host_name, uint16_t port); + + calc_t get_max_prime() const; + std::vector get_last_n(calc_t n) const; + void calculate(calc_t n) const; +}; \ No newline at end of file diff --git a/03_UDP/include/Network.h b/03_UDP/include/Network.h new file mode 100644 index 0000000..be4685b --- /dev/null +++ b/03_UDP/include/Network.h @@ -0,0 +1,51 @@ +#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: + static const size_t MAX_LEN = 500; + static const size_t TIME_OUT_SEC = 5; + + std::string _host_name; + uint16_t _port; + + int try_send_message(char* message, size_t message_length, char* response) const; + uint64_t get_check_sum(const std::vector &v, size_t prefix_length) const; + size_t data2message(const std::vector &message_data, size_t size_num, char* message) const; + int massage2data(char* response, int response_length, size_t size_num, std::vector &response_data) const; + +public: + Network(std::string host_name, uint16_t port); + + std::vector send_message(const std::vector &v, size_t size_num) const; +}; \ No newline at end of file diff --git a/03_UDP/include/SimpleChecker.h b/03_UDP/include/SimpleChecker.h new file mode 100644 index 0000000..4e68242 --- /dev/null +++ b/03_UDP/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/03_UDP/src/Client.cpp b/03_UDP/src/Client.cpp new file mode 100644 index 0000000..b83f9b8 --- /dev/null +++ b/03_UDP/src/Client.cpp @@ -0,0 +1,70 @@ +#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 +{ + vector message; + message.push_back((uint64_t)CODE_GET_MAX_SIMPLE); + + vector response; + do { + response = _network.send_message(message, sizeof(calc_t)); + } while (response.size() != 1); + + calc_t res = (calc_t)response[0]; + return res; +} + +vector Client::get_last_n(calc_t n) const +{ + vector message; + message.push_back((uint64_t)CODE_GET_LAST_N); + message.push_back((uint64_t)n); + + vector response; + do { + response = _network.send_message(message, sizeof(calc_t)); + } while (response.size() == 0 || response[0] + 1 != response.size()); + + vector res; + for (size_t i = 1; i < response.size(); i++) { + res.push_back((calc_t)response[i]); + } + return res; +} + +void Client::calculate(calc_t n) const +{ + vector message; + message.push_back((uint64_t)CODE_CALCULATE); + message.push_back((uint64_t)n); + + vector response; + do { + response = _network.send_message(message, sizeof(calc_t)); + } while (response.size() != 1); + + calc_t start_num = (calc_t)response[0]; + + vector prime_nums = SimpleChecker::check_interval(start_num, n); + + message.clear(); + message.push_back((uint64_t)CODE_SEND_CALCULATED); + message.push_back((uint64_t)n); + message.push_back((uint64_t)start_num); + message.push_back((uint64_t)prime_nums.size()); + for (uint64_t x : prime_nums) { + message.push_back(x); + } + + do { + response = _network.send_message(message, sizeof(calc_t)); + } while (response.size() != 0); +} \ No newline at end of file diff --git a/03_UDP/src/Network.cpp b/03_UDP/src/Network.cpp new file mode 100644 index 0000000..8f6a2c9 --- /dev/null +++ b/03_UDP/src/Network.cpp @@ -0,0 +1,121 @@ +#include "Network.h" + +using std::vector; +using std::string; + +Network::Network(string host_name, uint16_t port) +: _host_name(host_name), _port(port) +{} + +int Network::try_send_message(char* message, size_t message_length, char* response) const +{ + int sockfd = socket(AF_INET, SOCK_DGRAM, 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); + + struct timeval tv; + tv.tv_sec = TIME_OUT_SEC; + tv.tv_usec = 0; + if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + throw NetworkException("Could not set timeout"); + } + + int n; + n = sendto(sockfd, (const char *)message, message_length, MSG_CONFIRM, (const struct sockaddr *) &serv_addr, sizeof(serv_addr)); + if (n == -1) { + close(sockfd); + return -1; + } + + socklen_t len; + n = recvfrom(sockfd, (char *)response, MAX_LEN, MSG_WAITALL, (struct sockaddr *) &serv_addr, &len); + + close(sockfd); + return n; +} + +uint64_t Network::get_check_sum(const vector &v, size_t prefix_length) const +{ + size_t len = v.size(); + if (len > prefix_length) { + len = prefix_length; + } + + uint64_t sum = 0; + for (size_t i = 0; i < len; i++) { + sum += v[i]; + } + + return sum; +} + +size_t Network::data2message(const vector &message_data, size_t size_num, char* message) const +{ + char* pointer = message; + for (uint64_t x : message_data) { + bcopy((const char *)&x, pointer, size_num); + pointer += size_num; + } + + uint64_t sum = get_check_sum(message_data, message_data.size()); + bcopy((const char *)&sum, pointer, size_num); + pointer += size_num; + + return size_num * (message_data.size() + 1); +} + +int Network::massage2data(char* response, int response_length, size_t size_num, vector &response_data) const +{ + if (response_length == -1 || response_length == 0) { + return -1; + } + + if (response_length % size_num != 0) { + return -1; + } + + char* pointer = response; + response_length /= size_num; + while (response_length--) { + uint64_t x; + bcopy(pointer, (char *)&x, size_num); + pointer += size_num; + response_data.push_back(x); + } + + if (response_data.back() != get_check_sum(response_data, response_data.size() - 1)) { + return -1; + } + + response_data.pop_back(); + + return 0; +} + +vector Network::send_message(const vector &message_data, size_t size_num) const +{ + char message[MAX_LEN]; + size_t message_length = data2message(message_data, size_num, message); + + char response[MAX_LEN]; + int response_length; + vector response_data; + do { + response_length = try_send_message(message, message_length, response); + } while (massage2data(response, response_length, size_num, response_data) == -1); + + return response_data; +} \ No newline at end of file diff --git a/03_UDP/src/SimpleChecker.cpp b/03_UDP/src/SimpleChecker.cpp new file mode 100644 index 0000000..c351580 --- /dev/null +++ b/03_UDP/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/03_UDP/src/main.cpp b/03_UDP/src/main.cpp new file mode 100644 index 0000000..f31c286 --- /dev/null +++ b/03_UDP/src/main.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include "Client.h" + +using namespace std; + +static const calc_t MAX_N = 50; + +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") { + calc_t n; + cin >> n; + if (n > MAX_N) { + cout << "n should not be more than " << MAX_N << endl; + continue; + } + vector v = client.get_last_n(n); + for (calc_t x : v) + cout << x << " "; + cout << endl; + } else if (command == "calculate") { + calc_t n; + cin >> n; + if (n > MAX_N) { + cout << "n should not be more than " << MAX_N << endl; + continue; + } + 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