diff --git a/lab1_client/.gitignore b/lab1_client/.gitignore new file mode 100644 index 0000000..831205f --- /dev/null +++ b/lab1_client/.gitignore @@ -0,0 +1 @@ +lab1_client diff --git a/lab1_client/CMakeLists.txt b/lab1_client/CMakeLists.txt new file mode 100644 index 0000000..a665566 --- /dev/null +++ b/lab1_client/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.8) +project(lab1_client) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") + +set(SOURCE_FILES main.cpp client.cpp client.h) +add_executable(lab1_client ${SOURCE_FILES}) \ No newline at end of file diff --git a/lab1_client/client.cpp b/lab1_client/client.cpp new file mode 100644 index 0000000..292ab02 --- /dev/null +++ b/lab1_client/client.cpp @@ -0,0 +1,188 @@ +#include "client.h" + +Client::Client(string host, int portno) { + /* Create a socket point */ + sockfd = socket(AF_INET, SOCK_STREAM, 0); + + if (sockfd < 0) { + perror("ERROR opening socket"); + exit(1); + } + + struct hostent *server = gethostbyname(host.c_str()); + struct sockaddr_in serv_addr; + + if (server == NULL) { + fprintf(stderr, "ERROR, no such host\n"); + exit(0); + } + + bzero((char *) &serv_addr, 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(portno); + + /* Now connect to the server */ + if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + perror("ERROR connecting"); + exit(1); + } + + pthread_mutex_init(&mutex, NULL); +} + +Client::~Client() { + pthread_mutex_destroy(&mutex); +} + +rw_t read_num(int sockfd) { + rw_t buffer[2]; + bzero(buffer, sizeof(rw_t) * 2); + ssize_t n; + n = read(sockfd, buffer, sizeof(rw_t)); + if (n <= 0) { + throw rw_exception("ERROR reading from socket"); + } + return buffer[0]; +} + +void write_nums(int sockfd, vector nums) { + rw_t buffer[256]; + ssize_t n; + for (int i = 0; i < nums.size();) { + int j = 0; + for (; j < 255 && i + j < nums.size(); j++) { + buffer[j] = *nums[i + j]; + } + n = write(sockfd, buffer, sizeof(rw_t) * j); + if (n < 0) { + throw rw_exception("ERROR writing to socket"); + } + i += j; + } +} + +rw_t get_res(int sockfd, Client* client) { + rw_t t = read_num(sockfd); + while (t == 3) { + rw_t id = read_num(sockfd); + rw_t res = read_num(sockfd); + cout << "Result of query " << id << " "; + type tp = client->get_long_query(id); + if (tp == SQRT) + cout << "(get_sqrt) is " << *((calc_t*)&res); + else if (tp == FACT) + cout << "(get_fact) is " << *((fact_t*)&res); + cout << endl; + t = read_num(sockfd); + } + return read_num(sockfd); +} + +void *listen(void* args) { + Client* client = ((task_args*) args)->client; + int sockfd = ((task_args*) args)->sockfd; + while (true) { + pthread_mutex_lock(client->get_mutex()); + rw_t buf[4]; + bzero(buf, sizeof(rw_t) * 4); + int flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + int n = read(sockfd, buf, 3 * sizeof(rw_t)); + fcntl(sockfd, F_SETFL, flags); + if (n > 0) { + while (n < 3 * sizeof(rw_t)) { + int m = read(sockfd, ((char*)buf) + n, 3 * sizeof(rw_t) - n); + n += m; + } + rw_t id = buf[1]; + rw_t res = buf[2]; + cout << "Result of query " << id << " "; + type tp = client->get_long_query(id); + if (tp == SQRT) + cout << "(get_sqrt) is " << *((calc_t*)&res); + else if (tp == FACT) + cout << "(get_fact) is " << *((fact_t*)&res); + cout << endl; + } + pthread_mutex_unlock(client->get_mutex()); + sleep(5); + } +} + +void Client::run() { + + cout << "List of commands\n" + "List of commands:\n" + "1. get_sum \n" + "2. get_mult \n" + "3. get_diff \n" + "4. get_quot \n" + "5. get_sqrt \n" + "6. get_fact \n" + "7. exit\n" + ; + + pthread_t *thread = (pthread_t*) malloc(sizeof(pthread_t)); + pthread_create(thread, NULL, listen, new task_args(this, sockfd)); + + string command; + while (cin >> command) { + rw_t type; + if (command == "get_sum") { + type = 1; + } else if (command == "get_mult") { + type = 3; + } else if (command == "get_diff") { + type = 2; + } else if (command == "get_quot") { + type = 4; + } else if (command == "get_sqrt") { + type = 6; + } else if (command == "get_fact") { + type = 5; + } else if (command == "exit") { + pthread_kill(*thread, 0); + free(thread); + close(sockfd); + return; + } else { + cerr << "Incorrect command" << endl; + continue; + } + if (type >= 1 && type <= 4) { + calc_t a, b; + cin >> a >> b; + pthread_mutex_lock(&mutex); + write_nums(sockfd, {&type, (rw_t*) &a, (rw_t*) &b}); + rw_t store = get_res(sockfd, this); + calc_t res = *((calc_t*) &store); + pthread_mutex_unlock(&mutex); + cout << "Result of query " << command << " is " << res << endl; + } else if (type == 6) { + calc_t a; + cin >> a; + pthread_mutex_lock(&mutex); + write_nums(sockfd, {&type, (rw_t*) &a}); + rw_t id = get_res(sockfd, this); + long_queries[id] = SQRT; + pthread_mutex_unlock(&mutex); + cout << "Query " << command << " is queued with id " << id << endl; + } else if (type == 5) { + fact_t n; + cin >> n; + pthread_mutex_lock(&mutex); + write_nums(sockfd, {&type, (rw_t*) &n}); + rw_t id = get_res(sockfd, this); + long_queries[id] = FACT; + pthread_mutex_unlock(&mutex); + cout << "Query " << command << " is queued with id " << id << endl; + } + } +} + +pthread_mutex_t *Client::get_mutex() { return &mutex; } +type Client::get_long_query(rw_t id) { return long_queries[id];} + +task_args::task_args(Client *client, int sockfd): client(client), sockfd(sockfd) {} +rw_exception::rw_exception(const string &what): runtime_error(what) {} \ No newline at end of file diff --git a/lab1_client/client.h b/lab1_client/client.h new file mode 100644 index 0000000..844e6aa --- /dev/null +++ b/lab1_client/client.h @@ -0,0 +1,60 @@ +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +using std::string; +using std::set; +using std::vector; +using std::max; +using std::min; +using std::cin; +using std::cout; +using std::cerr; +using std::endl; +using std::runtime_error; +using std::map; + +typedef unsigned long long fact_t; +typedef unsigned long long rw_t; +typedef double calc_t; + +enum type { SQRT, FACT }; + +class Client { +public: + Client(string host, int portno); + ~Client(); + void run(); + pthread_mutex_t *get_mutex(); + type get_long_query(rw_t id); +private: + int sockfd; + pthread_mutex_t mutex; + map long_queries; +}; + +struct rw_exception : runtime_error { + rw_exception(const string &what); +}; + +struct task_args { + task_args(Client *client, int sockfd); + Client *client; + int sockfd; +}; \ No newline at end of file diff --git a/lab1_client/main.cpp b/lab1_client/main.cpp new file mode 100644 index 0000000..1cea0f1 --- /dev/null +++ b/lab1_client/main.cpp @@ -0,0 +1,16 @@ +#include "client.h" + +int main(int argc, char *argv[]) { + if (argc < 3) { + fprintf(stderr, "usage %s hostname port\n", argv[0]); + exit(0); + } + + uint16_t portno = (uint16_t) atoi(argv[2]); + + + Client client(argv[1], portno); + client.run(); + + return 0; +} \ No newline at end of file