Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lab1_client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lab1_client
9 changes: 9 additions & 0 deletions lab1_client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
188 changes: 188 additions & 0 deletions lab1_client/client.cpp
Original file line number Diff line number Diff line change
@@ -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<rw_t*> 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++) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Флаг устанавливается для сокета, т.е. в другой потоке сокет тоже становится неблокирующим. Вместо этого лучше указать флаг для recv.

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 <a> <b>\n"
"2. get_mult <a> <b>\n"
"3. get_diff <a> <b>\n"
"4. get_quot <a> <b>\n"
"5. get_sqrt <a>\n"
"6. get_fact <n>\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) {}
60 changes: 60 additions & 0 deletions lab1_client/client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <stdio.h>
#include <stdlib.h>

#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>

#include <string.h>

#include <pthread.h>
#include <signal.h>

#include <string>
#include <stdexcept>
#include <set>
#include <vector>
#include <iostream>
#include <map>

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<rw_t, type> 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;
};
16 changes: 16 additions & 0 deletions lab1_client/main.cpp
Original file line number Diff line number Diff line change
@@ -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;
}