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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

# Created by https://www.gitignore.io/api/c++,latex,cmake,netbeans,qtcreator,visualstudio

### Intellij IDEA ###
/.idea/*

### C++ ###
# Prerequisites
*.d
Expand Down
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.5)
project(NetworksLab2019HSE)

set(CMAKE_CXX_STANDARD 14)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Iinclude -pedantic -Wextra -pthread")

include_directories(./include)

add_executable(NetworksLab2019HSE
src/Client.cpp
src/CurrencyClientApplication.cpp
src/Currency.cpp
)
68 changes: 68 additions & 0 deletions CurrencyApplicationProtocol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
Протокол разрабатывается исходя из подхода "запрос-ответ", так как он очень хорошо подходит для задачи:
клиенты запрашивают какое-то действие с валютой, сервер ее выполняет.

Данные на сервере:
Массив валют, где валюта это:
Название валюты - 16 байта
История курса валюты - N * 4 байта (каждое значение курса это 4 байта)

... - повторение описанных блоков выше.

Клиент и сервер обмениваются пакетами размера 508 байт (либо меньше, если размер сообщения небольшой).
В начале каждого пакета с запросом клиент передает <request_id: 4 байта> -- номер его сессии,
и при получении ответа от сервера обрабатывает только те пакеты, которые соответствуют этой сессии.
Сделано это для того, чтобы если пакет от сервера задержался и запрос от клиента был отправлен повторно,
ошибочно не учитывать уже невалидный пакет. Таким образом, пакеты с неправильным id игнорируются.
Перед отправкой ответа с сервера содержимое сообщения разбивается на пакеты по 508 байт.
В начало каждого записывается служебная информация:
<request_id: 4 байта><num_packets: 4 байта><packet_id: 4 байта> -- номер сессии, количество пакетов и порядковый номер текущего соответственно.
Клиент расставляет пришедшие пакеты в правильном порядке, при нехватке пакетов отправляет запрос заново с новым номером сессии.

Поддерживаемые типы запросов:
0. Получение и вывод списка валют с котировками/изменениями
Номер команды: 0.

Клиент отправляет: "<номер команды: 4 байта>",

Сервер отвечает:
"<название валюты: 16 байт><текущий курс: 4 байта><есть ли предыдущий курс: 1 байт><абсолютное приращение: 4 байта><относительное приращение: 4 байта>"...,
если предыдущего курса нет, то абсолютное и относительное значения равны нулям и игнорируются,
относительное значение выражается в процентах и округляется до целых.
Формулы:
абсолютное = current - previous
относительное = (current * 100.0) / previous

1. Передача команды на добавление валюты
Номер команды: 1.

Клиент отправляет: "<номер команды: 4 байта><название валюты: 16 байт><текущий курс: 4 байта>",

Сервер отвечает:
"<успех запроса: 1 байт>",
возвращает 1 если такой валюты еще не было, 0 если такая валюта была.

2. Передача команды на удаление валюты
Номер команды: 2.

Клиент отправляет: "<номер команды: 4 байта><название валюты: 16 байт>",

Сервер отвечает:
"<успех запроса: 1 байт>",
возвращает 1 если такая валюта была и была удалена успешно, 0 если такой валюты не было.

3. Передача команды на добавление курса валюты
Номер команды: 3.

Клиент отправляет: "<номер команды: 4 байта><название валюты: 16 байт><новый курс: 4 байта>",

Сервер отвечает:
"<успех запроса: 1 байт>",
возвращает 1 если успешно выставлен новый курс, 0 иначе.

4. Получение истории котировок валюты
Номер команды: 4.

Клиент отправляет: "<номер команды: 4 байта><название валюты: 16 байт>",

Сервер отвечает:
"<курс1: 4 байта><курс2: 4 байта>"...
69 changes: 69 additions & 0 deletions include/Client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// Created by mikhail on 03.02.19.
//

#ifndef NETWORKSLAB2019HSE_CLIENT_H
#define NETWORKSLAB2019HSE_CLIENT_H


#include <unordered_map>
#include <map>
#include "Currency.h"

class Client {
public:
Client(const std::string &server_ip, uint16_t portno);

const std::vector<Currency> list();

bool addCurrency(const Currency &currency);

bool addRate(const Currency &currency, int32_t new_rate);

bool remove(const Currency &currency);

Currency getCurrencyWithHistory(const Currency &currency);

virtual ~Client();

private:
struct sockaddr_in *si_other;
const int sockfd;
int32_t request_id = 0;
int si_other_len;
static const size_t BUFFER_INITIAL_LENGTH = 1024;
static const size_t CURRENCY_NAME_SIZE_IN_LIST = 16;
static const size_t MAX_SIZE_OF_PACKET = 508;
static const size_t TIMOUT_SECONDS = 30;

const std::vector<int8_t> get_message_with_request_id(const std::vector<int8_t> &message);

const std::vector<int8_t> send_and_receive(const std::vector<int8_t> &message);

void write_request_id(std::vector<int8_t> &buffer);

bool is_all_packets_received(const std::map<int, std::vector<int8_t>> &packets, int number_of_packets) const;

std::vector<int8_t> construct_message_from_packets(const std::map<int, std::vector<int8_t>> &packets) const;

void write_command(std::vector<int8_t> &buffer, int32_t command_no) const;

const std::vector<Currency> translate_list_message(std::vector<int8_t> &message) const;

void write_string(std::vector<int8_t> &buffer, const std::string &currency_name) const;

void write_int32(std::vector<int8_t> &buffer, int32_t rate) const;

std::vector<int8_t> read_response() const;

bool translate_add_message(std::vector<int8_t> &message) const;

bool translate_remove_message(std::vector<int8_t> &message) const;

std::vector<int32_t> translate_get_currency_history_message(std::vector<int8_t> &message) const;

void send_request(const std::vector<int8_t> &buffer) const;
};


#endif //NETWORKSLAB2019HSE_CLIENT_H
46 changes: 46 additions & 0 deletions include/Currency.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Created by mikhail on 03.02.19.
//

#ifndef NETWORKSLAB2019HSE_CURRENCY_H
#define NETWORKSLAB2019HSE_CURRENCY_H


#include <string>
#include <vector>

class Currency {
public:
Currency(std::string name);

Currency(std::string name, std::vector<int32_t> rates);

Currency(std::string name, int32_t current_rate);

Currency(std::string name, int32_t current_rate, int32_t absolute_change, int32_t relative_change);

const std::string &get_name() const;

int32_t get_current_rate() const;

int32_t get_rate(size_t i) const;

const std::vector<int32_t>& get_rates() const;

int32_t get_absolute_change() const;

int32_t get_relative_change() const;

bool operator==(const Currency &rhs) const;

bool operator!=(const Currency &rhs) const;

private:
std::string name;
std::vector<int32_t> rates;
int32_t absolute_change;
int32_t relative_change;
};


#endif //NETWORKSLAB2019HSE_CURRENCY_H
26 changes: 26 additions & 0 deletions include/CurrencyClientApplication.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Created by mikhail on 03.02.19.
//

#ifndef NETWORKSLAB2019HSE_CURRENCYCLIENTAPPLICATION_H
#define NETWORKSLAB2019HSE_CURRENCYCLIENTAPPLICATION_H


#include "Client.h"

class CurrencyClientApplication {
public:
void run();

CurrencyClientApplication(const std::string &host, uint16_t portno);

private:
std::string host;
uint16_t portno;
Client client = Client(host, portno);

void printUsage();
};


#endif //NETWORKSLAB2019HSE_CURRENCYCLIENTAPPLICATION_H
Loading