From 4b853b15d12b8f772309645749b7bbcd26bb081e Mon Sep 17 00:00:00 2001 From: murfel Date: Tue, 19 Feb 2019 23:21:50 +0300 Subject: [PATCH 1/2] init --- tcp/client/client.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tcp/client/client.cpp diff --git a/tcp/client/client.cpp b/tcp/client/client.cpp new file mode 100644 index 0000000..e69de29 From b368f74ba9bf793c04735a626ddc3e7edcd28ee3 Mon Sep 17 00:00:00 2001 From: murfel Date: Tue, 26 Mar 2019 13:58:33 +0300 Subject: [PATCH 2/2] init --- tcp/client/CMakeLists.txt | 6 ++ tcp/client/client.cpp | 2 + tcp/client/client.h | 159 ++++++++++++++++++++++++++++++++++++++ tcp/client/main.cpp | 97 +++++++++++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 tcp/client/CMakeLists.txt create mode 100644 tcp/client/client.h create mode 100644 tcp/client/main.cpp diff --git a/tcp/client/CMakeLists.txt b/tcp/client/CMakeLists.txt new file mode 100644 index 0000000..a107183 --- /dev/null +++ b/tcp/client/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.12) +project(client) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(client main.cpp) \ No newline at end of file diff --git a/tcp/client/client.cpp b/tcp/client/client.cpp index e69de29..a65234b 100644 --- a/tcp/client/client.cpp +++ b/tcp/client/client.cpp @@ -0,0 +1,2 @@ +#include "client.h" + diff --git a/tcp/client/client.h b/tcp/client/client.h new file mode 100644 index 0000000..3a96a6d --- /dev/null +++ b/tcp/client/client.h @@ -0,0 +1,159 @@ +#ifndef CLIENT_CLIENT_H +#define CLIENT_CLIENT_H + +#include +#include +#include +#include +#include + + +int fd_set_blocking(int fd, int blocking) { + int flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) + return 0; + + if (blocking) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; + return fcntl(fd, F_SETFL, flags) != -1; +} + + +class client { +private: + int client_id_; + int sockfd_; + + void write_header(int operation_type) { + write(sockfd_, (char *) &operation_type, sizeof(operation_type)); + write(sockfd_, (char *) &(this->client_id_), sizeof(this->client_id_)); + } + + uint32_t read_uint32_t() { + uint32_t num; + read(sockfd_, (char *) & num, sizeof(num)); + return num; + } + + std::string read_uint32_t_and_convert_to_string() { + return std::to_string(read_uint32_t()); + } + + std::string read_create_order_response() { + return read_uint32_t_and_convert_to_string(); + } + + std::string read_retrieve_history_response() { + uint32_t num_orders = read_uint32_t(); + std::string response = "Number of orders: " + std::to_string(num_orders) + "\n"; + for (int i = 0; i < num_orders; i++) { + uint32_t client_id = read_uint32_t(); + uint32_t shop_id = read_uint32_t(); + uint32_t num_goods = read_uint32_t(); + + response += "Order #" + std::to_string(i) + ":\n"; + response += "Client ID: " + std::to_string(client_id) + ":\n"; + response += "Shop ID: " + std::to_string(shop_id) + ":\n"; + response += "Num goods: " + std::to_string(num_goods) + ":\n"; + response += "Goods numbers: "; + for (int j = 0; j < num_goods; j++) { + uint32_t good_id = read_uint32_t(); + response += std::to_string(good_id); + } + response += "\n\n"; + } + return response; + } + + std::string read_add_shop_response() { + return read_uint32_t_and_convert_to_string(); + } + + std::string read_disconnect_response() { + return ""; + } +public: + client(const std::string & hostname, int port, int client_id) : client_id_(client_id) { + struct hostent * host = gethostbyname(hostname.data()); + struct sockaddr_in serv_addr{}; + // Create socket. + sockfd_ = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd_ < 0) { + perror("ERROR opening socket"); + exit(1); + } + // Validate host + if (host == nullptr) { + fprintf(stderr, "ERROR, no such host\n"); + exit(0); + } + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + bcopy(host->h_addr, (char *) &serv_addr.sin_addr.s_addr, (size_t) host->h_length); + serv_addr.sin_port = htons(port); + } + + std::string receive_incoming_event() { + fd_set_blocking(sockfd_, true); + int32_t type = 0; + ssize_t n = read(sockfd_, (char *) &type, sizeof(type)); + if (n == 0) + return {}; + fd_set_blocking(sockfd_, false); + + switch (type) { + case 1: { + return read_create_order_response(); + } + case 2: { + return read_retrieve_history_response(); + } + case 3: { + return read_add_shop_response(); + } + case 4: { + return read_disconnect_response(); + } + default: { + return "Unknown response from the server."; + } + } + } + + void create_order(int shop_id, const std::vector & goods_ids) { + const int operation_type = 1; + this->write_header(operation_type); + write(sockfd_, (char *) & shop_id, sizeof(shop_id)); + int num_goods = goods_ids.size(); + write(sockfd_, (char *) & num_goods, sizeof(num_goods)); + for (int good_id : goods_ids) { + write(sockfd_, (char *) & good_id, sizeof(good_id)); + } + } + + void retrieve_order_history() { + const int operation_type = 2; + this->write_header(operation_type); + } + + void add_new_shop(const std::vector & goods_ids, int zone_id) { + const int operation_type = 3; + this->write_header(operation_type); + int num_goods = goods_ids.size(); + write(sockfd_, (char *) & num_goods, sizeof(num_goods)); + for (int good_id : goods_ids) { + write(sockfd_, (char *) & good_id, sizeof(good_id)); + } + write(sockfd_, (char *) & zone_id, sizeof(zone_id)); + } + + void disconnect() { + const int operation_type = 4; + this->write_header(operation_type); + } +}; + + +#endif //CLIENT_CLIENT_H diff --git a/tcp/client/main.cpp b/tcp/client/main.cpp new file mode 100644 index 0000000..d0b3156 --- /dev/null +++ b/tcp/client/main.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include "client.h" + +void process_incoming_event(client *client1) { + std::string incoming_event = client1->receive_incoming_event(); + if (incoming_event.empty()) { + std::cout << "Server has disconnected. Bye!" << std::endl; + exit(0); + } + std::cout << client1->receive_incoming_event(); +} + +int main(int argc, char * argv []) { + if (argc < 3) { + std::cout << "Usage: hostname port" << std::endl; + exit(1); + } + + std::cout << "Please enter your client ID: "; + int client_id; + std::cin >> client_id; + + client * client1 = new client(argv[0], atoi(argv[1]), client_id); + + std::cout << "Connected to the food server" << std::endl; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-noreturn" + while (true) { + std::cout << "Please choose an action:" << std::endl; + std::cout << "[c]reate order" << std::endl; + std::cout << "[r]etrieve order history" << std::endl; + std::cout << "[a]dd a new shop" << std::endl; + std::cout << "[d]isconnect" << std::endl; + + char input; + std::cin >> input; + + switch (input) { + case 'c': { + std::cout << "Creating an order" << std::endl; + std::cout << "Please enter information in the following format: " + "shop_id num_goods goods_ids{num_goods}" << std::endl; + int shop_id; + int num_goods; + std::cin >> shop_id >> num_goods; + std::vector goods_ids(num_goods); + for (int &good_id : goods_ids) { + std::cin >> good_id; + } + client1->create_order(shop_id, goods_ids); + process_incoming_event(client1); + break; + } + case 'r': { + std::cout << "Retrieving an order" << std::endl; + client1->retrieve_order_history(); + process_incoming_event(client1); + break; + } + case 'a': { + std::cout << "Adding a new shop" << std::endl; + std::cout << "Please enter information in the following format:" + "num_goods goods_ids{num_goods} zone_id" << std::endl; + int num_goods; + std::cin >> num_goods; + std::vector goods_ids(num_goods); + for (int & good_id : goods_ids) { + std::cin >> good_id; + } + int zone_id; + std::cin >> zone_id; + client1->add_new_shop(goods_ids, zone_id); + process_incoming_event(client1); + break; + } + case 'd': { + std::cout << "Disconnecting. Bye!" << std::endl; + client1->disconnect(); + delete client1; + exit(0); + break; + } + default: { + std::cout << "Incorrect input: " << input << std::endl; + break; + } + } + + + } +#pragma clang diagnostic pop + + return 0; +} \ No newline at end of file