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
66 changes: 66 additions & 0 deletions udp/CurrencyApplicationProtocol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
Протокол разрабатывается исходя из подхода "запрос-ответ", так как он очень хорошо подходит для задачи:
клиенты запрашивают какое-то действие с валютой, сервер ее выполняет.

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

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

Клиент и сервер обмениваются пакетами раземра 508 байт (либо меньше, если размер сообщения небольшой).
В начале каждого пакета с запросом клиент передает <request_id: 4 байта> -- номер его сессии,
и при получении ответа от сервера обрабатывает только те пакеты, которые соответствуют этой сессии.
Перед отправкой ответа с сервера содержимое сообщения разбивается на пакеты по 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 байта>"...
14 changes: 14 additions & 0 deletions udp/server/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.5)
project(homework02)

set(CMAKE_CXX_STANDARD 11)
find_package(Threads REQUIRED)

include_directories(.)

add_executable(homework02
src/CurrencyServerApplication.cpp
src/Server.cpp include/Server.h
src/Currency.cpp include/Currency.h)

target_link_libraries(homework02 Threads::Threads)
33 changes: 33 additions & 0 deletions udp/server/include/Currency.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef CURRENCY_H
#define CURRENCY_H

#include <vector>
#include <string>

class Currency {
public:
static const int32_t ABSENT_CHANGE_VALUE = -1;

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

const std::string &getName() const;

int32_t getCurrentRate() const;

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

void addRate(int32_t rate);

int32_t getAbsoluteChange() const;

int32_t getRelativeChange() const;

private:
std::string name;
std::vector<int32_t> rates;
int32_t absoluteChange;
int32_t relativeChange;
};

#endif // CURRENCY_H

51 changes: 51 additions & 0 deletions udp/server/include/Server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef SERVER_H
#define SERVER_H

#include <vector>
#include <map>
#include <cstddef>

#include "include/Currency.h"

class Server {
public:
Server(uint16_t portNumber);

void start();

void stop() const;

private:
void processCurrencyListQuery();
void processNewCurrencyQuery();
void processDeleteCurrencyQuery();
void processAddCurrencyRateQuery();
void processCurrencyRateHistoryQuery();

int32_t readRequestId();
int32_t readCommand();
const std::string readCurrencyName();
int32_t readCurrencyRate();

int32_t readInt32();
void readChars(char *dst, size_t size);

void sendString(const std::string &message, size_t len);
void sendInt32(int32_t n);
void sendInt8(int8_t n);

void checkStatus(int n) const;

static const int CURRENCY_NAME_SIZE = 16;
static const size_t BUFFER_SIZE = 508;
int8_t buffer[BUFFER_SIZE];
int bufferPosition;
std::vector<int8_t> message;
std::map<std::string, Currency> currencies;

int sockfd;
uint16_t portNumber;
};

#endif // SERVER_H

41 changes: 41 additions & 0 deletions udp/server/src/Currency.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "include/Currency.h"

#include <iostream>
#include <cstdint>
#include <string>

using namespace std;

Currency::Currency(string name, int32_t currentRate) : name(move(name)) {
rates = {currentRate};
absoluteChange = ABSENT_CHANGE_VALUE;
relativeChange = ABSENT_CHANGE_VALUE;
}

const string &Currency::getName() const {
return name;
}

int32_t Currency::getCurrentRate() const {
return rates[rates.size() - 1];
}

const vector<int32_t> &Currency::getRates() const {
return rates;
}

void Currency::addRate(int32_t rate) {
int32_t lastRate = getCurrentRate();
rates.push_back(rate);
absoluteChange = rate - lastRate;
relativeChange = static_cast<int32_t>((rate * 100.0) / lastRate);
}

int32_t Currency::getAbsoluteChange() const {
return absoluteChange;
}

int32_t Currency::getRelativeChange() const {
return relativeChange;
}

50 changes: 50 additions & 0 deletions udp/server/src/CurrencyServerApplication.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <iostream>
#include <string>
#include <pthread.h>

#include "include/Server.h"

using namespace std;

int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "usage: .%s <port>\n", argv[0]);
return 0;
}
long portNumber = strtol(argv[1], nullptr, 10);

if (portNumber <= 0 || portNumber > UINT16_MAX) {
fprintf(stderr, "illegal port number\n");
return 0;
}

Server server(static_cast<uint16_t>(portNumber));
pthread_t serverThread;
typedef void * (*PTHREAD_FUNC_PTR)(void *);

int rc = pthread_create(&serverThread,
nullptr,
(PTHREAD_FUNC_PTR) &Server::start,
&server);

if (rc) {
cout << "Failed to create server." << endl;
exit(1);
}

std::string input;
while (true) {
cin >> input;

if (input == "q") {
server.stop();
break;
}
}

void *status;
pthread_join(serverThread, &status);

return 0;
}

Loading