Клиент хочет получить набор блоков данных переменного размера(1Байт-1Мегабайт) от сервера. Блоки данный идентифицируются по хэшу(например sha1, длина 128 байт). Список хэшей необходимых блоков клиент должен отправить серверу. В ответ сервер должен отправить блоки данных соответствующие запрошенным хэшам клиенту, при этом нужно предусмотреть что размер блоков может быть переменным. Блоки данных на сервере располагаются в блочном устройстве, в случайном порядке. Сервер неким волшебным образом очень быстро может узнать номер блока в блочном устройстве по хэшу с помощью функции - size_t get_block_number(const string& hash). Сервер неким волшебным образом очень быстро может вернуть реальный размер блока в байтах с помощью функции - size_t get_block_size(const string& hash). Сервер неким волшебным образом очень быстро может прочитать данные из блочного устройства с помощью функции - int get_block_data(size_t block_num, char* buffer, size_t buffer_size).
Задача:
Наиболее элегантным образом, с особым вниманием к производительности, реализовать серверную часть протокола взаимодействия клиента и сервера для получения блоков данных клиентом. Также учесть что количество запрашиваемых блоков может быть очень большим.
Структура проекта выглядит таким образом:
.
├── CMakeLists.txt - cmake проекта
├── README.md - текущий файл
├── client
│ └── client.py - клиент для подключения к серверу
├── lib
│ ├── CMakeLists.txt - cmake сторонних библиотек
│ └── clsocket - библиотека сокет
└── server
├── CMakeLists.txt - cmake серверной части
├── block.cpp
├── block.h - класс блочного девайса
├── main.cpp
├── server.cpp
└── server.h - класс сервера
Серверная часть работает следующим образом:
- Из главного потока создается и запускается экземпляр сервера. При этом считается, что блочный девайс - директория
/tmp
. Это сделано в качестве заглушки и демонстрации решения. - Сервер запускает поток, слушающий сокет
localhost
на порте4000
. Ждет подключение клиента. - Если подключение успешно создано, ждет хэш от клиента. Хэш ограничен 40 байтами. Получает номер блока, размер блока, данные блока. Шлет данные клиенту. Буффер данных ограничен 256 байтами. Если новых сообщений не поступает, поток завершает работу. Иначе просто завершает работу с соответствующем выводом в консоль.
- Главный поток ждет остановки при помощи ввода симвода
q
с клавиатуры. После ввода символа, программа завершает работу.
Реализует интерфейс InterfaceServer
. Необходим для обеспечения подключения клиента, получения сообщений и отправки данных. Использует два потока - главный и поток обработки подключения.
Необходим для серверной части. Реализует блочный девайс с функциями:
get_block_number
get_block_size
get_block_data
Использует в качестве единицы хранения путей к файлам std::vector.
Реализуется при помощи Python
скрипта, использующего библиотеку socket
. Работает следующим образом:
- Создает сокет
"127.0.0.1":4000
- Отправлет заранее заданную строку (hash) серверу. Выводит лог отправки сообщения. Ждет ответ.
- После получения ответа, выводит его в консоль. Завершает работу.
Используется блокирующий сокет.
-
Сгенерируйте какие-то файлы с названием длины
40
(sha1 hash size
) в директории/tmp
. Например,"356a192b7913b04c54574d18c28d46e6395428a1"
c содержимым"qwerty!\n"
-
Соберите и запустите сервер
mkdir build
cd build
cmake ..
ninja
cd build/server
./server
Server::Server()
"/tmp/356a192b7913b04c54574d18c28d46e6395428a1" 8
Server::Start() : start
Enter 'q' to quit
Server::start_listen() : start 0x16ef77000
- Запустите клиент
cd client
python3 client.py
(base) ➜ client git:(main) ✗ python3 client.py
-----START-----
SEND 356a192b7913b04c54574d18c28d46e6395428a1
RECEIVE qwerty!
Вывод сервера будет примерно таким
Server::receive_msg() m: 356a192b7913b04c54574d18c28d46e6395428a1 b: 40
BlockDevice::get_block_number() 356a192b7913b04c54574d18c28d46e6395428a1
BlockDevice::get_block_size() 0
BlockDevice::get_block_data() 0 8
Server::send_msg() b: 8
Server::receive_msg() : the connection has been shutdown on the other side
Server::start_listen() : stop
- Введите символ "q" в консоль, чтобы завершить работу сервера.
q
Server::Stop() : stop
Server::~Server()
- MacOS silicon
clang 14.0.3 arm64-apple-darwin22.5.0
python 3.11.6
- Linux Mint 20.04
gcc 9.4.0 glibc 2.31
python 3.9.12