Проект написан, в рамках изучения мной сетевого фреймворка Netty, я решил создать облачную систему хранения файлов с Netty в качестве ядра. Мной рассматривалось два варианта реализации прикладного протокола взаимодействия между сервером и клиентом. Первый вариант, это работа с передаваемыми байтами через ByteBuffer Netty, и второй это работать с настроенными PipeLine фильтром (который, к слову все так же работает с ByteBuffer, ведь все, что летит по сети - это Байты! ), в котором использовать фильтры сериализации исходящих сообщений и десериализации входящих. Я выбрал второй вариант - работать с объектами, хотя протокол написанный мной в рамках другого проекта с байтами показал большую эффективность.
Netty — это инфраструктура клиент/сервер, которая использует расширенные сетевые возможности Java, скрывая за собой сложность и предоставляя простой в использовании API.
В рамках проекта реализованно:
- Сервер Netty запускается и подключает клиентов, пересылает служебные сообщения от клиентов (котороые так же могут нести в себе данные из файла), отвечает за авторизацию пользователей, использует
Data Base SQLite, для хранения данных пользователей (работа с Data Base черезJDBC), распределяет и контроллирует выделяемое под пользователей дисковое пространство, по запросу от клиентов проводит действия на закрепленном за пользователем дисковом пространстве. - Клиент Java FX запускаясь предлагает пользователю авторизоваться и при успехе предоставляет доступ к основному графическому интерфейсу
(GUI).GUIпоказывает состояние хранилища для пользователя: наличие файлов и их свойства, общую наполненность до10 Gb(это размер дискогвого пространства, выделяемого каждому пользователю на сервере). Так жеGUIсодержит элементы управления позволяющие выполнять следующие действия.- Принять и записать файлы пользователя.
- Передать файлы пользователю.
- Удалить файлы с дискового пространства пользователя.
Техническая часть
IDE: IntelliJ IDEA 2021.3.3Версия JDK: 1.8.0_121 + 16 на стороне клиента.Netty FrameworkSQLite
Используемые технологии:
Java FXJava IO, NIOStream APINettyCSSJDBCМавен 3.5
Вид программы в Production.
Передача данных между клиентом и сервером основанна на Object Message, сообщения могут содержать данные из передаваемых файлов и не превышают лимит в 10 Mb. При передаче файлов больших размеров файл разрезается на куски и по частям пересылается.
Когда запускается сервер Netty, в нем настраивается конвеер Pipe Line для обработки получаемых из сети данных. Все данные получаемые приложением из сети попадают в Byte Bufer сервера Netty и проходят через Pipe Line до Main Handler'a. Для обработки полученных байтов из Byte Buffer'a используются сериализатор и десериализатор. Полученные таким образом объекты приходят в конечную точку Pipe Line в MainHandler. Если необходимо отправить сообщение в сеть, происходит обратный процесс пошаговой обработки в Pipe Line. Сдесь нужно сказать, что элементы PipeLine могут обрабатывать как входящий поток так и исходящий или быть как MainHandler конечной точкой.
Object Decoder- Декодер, десериализует полученный байтовый буфер в объекты Java.Object Encoder- Кодировщик, который сериализует объект Java в байтбуфер.MainHandler- является точкой соприкосновения cо всеми сервисами программы.
Нужно упоминуть, что для каждого подключаемого клиента создается свой PipeLine содержащий все элементы, и так же MainHandler. Создавая новый PipeLine, MainHandler получает ссылку на сервис авторизации и запускает регистратор слушателей служебных сообщений RegistryHandler прописывающий в себе ссылки на методы обработки входящих сообщений по их типу (патерн Registry). При получении из PipeLine входящего объекта сообщения в MainHandler вызывается RegistryHandler и из него достается зарегистрированный под этот тип сообщения слушатель - свой Handler и выполняется метод для обработки пришедшего сообщения.
Регистрация слушателей.
...
private Map<Class<? extends AbstractMessage>, RequestHandler> mapHandlers;
...
public RegistryHandler(Controller controller) {
this.mapHandlers = new HashMap<>();
mapHandlers.put(AuthMessage.class, new AuthHandler(controller)::authHandle);
mapHandlers.put(RegUserRequest.class, new RegUserHandler(controller)::regHandle);
mapHandlers.put(FileMessage.class, new FileHandler(controller)::fileHandle);
mapHandlers.put(FilesSizeRequest.class, new FilesSizeRequestHandler(controller)::filesSizeReqHandle);
}
Где RequestHandler является функциональным интерфейсом
@FunctionalInterface
public interface RequestHandler {
void handle(ChannelHandlerContext ctx, Object msg);
}
Схема обработки входящих сообщений в
MainHandler
Используются следующие зарегистрированные слушатели:
AuthHandler- Используя сервис авторизации пользователей, выполняет авторизацию пользователя на сервере. (для хранения данных пользователей используется локальная SQLite база данных). При успешной авторизации на сервере предоставляет доступ к рабочему функционалу облака.DelFileHandler- Удаляет файл из облака пользователя.FileHandler- Получает сообщение с данными файла и записывает на диск.FilesListRequestHandler- Отвечает на запрос о состояние Облака, для пользователя, отправившего запрос.FileHandler- Обрабатывает запрос на регистрацию нового пользователя, проверяет, есть ли в базе данных пользователь с таким же ником, если есть, то отправляет отказ в регистрации, а при отсутствии регистрирует его и отправляет ответ клиенту, что регистрация прошла успешно.ReqFileHandler- Обрабатывает запрос от клиента на получение файла, если файл весит более 10 Мб, разрезает его на части по 10 Мб. и отправляет клиенту.
Получение
MainHandler'omобъекта сообщения из конвеераNettyи обработка с помощьюHandlerRegistry- паттерн Registry.
public void channelRead(ChannelHandlerContext ctx, Object msg){
RequestHandler handler = registryHandler.getHandler(msg.getClass());
handler.handle(ctx, msg);
}
Сила функциональных интерфейсов в том, что если метод по сигнатуре параметров совпадает с методом фунциоанального интерфейса, то можно сохранить ссылку на этот метод обработчика из registryHandler в переменной handler интерфейса RequestHandler. И в завершении вызвать метод интерфейса handle(ctx, msg) передав ему одинаковые параметры для выполнения метода из registryHandler.
На стороне клиента архитектура сетевого взаимодействия такая же, как и на сервере: с разницей в реализуемом клиенте Netty. В клиенте так же настраивается PipeLine с декодером, энкодером и MainHandler'om, в котором зарегистрированные слушатели получают объекты сообщений.
При старте приложения запускается форма ввода логина и пароля.
Если аккаунта нет, можно перейти по ссылке "Don't hаve an accaunt?" и произойдет смена панелей. Панель ввода логина и пароля станет неактивной и вместо нее активный фокус заберет панель регистрации нового пользователя.
Обе формы принимающие пользовательский ввод, проверяют корректность заполнения предлагаемых полей. К примеру если в форме авторизации не ввести логин или пароль, то соединение для передачи информации не будет открыто! Потому что, обработчик выдаст ошибку и подсветит текстовую метку красным цветом, картинка ниже.
Если все впорядке и данные введены, будет созданно сетевое подключение и сообщение авторизации AuthMessage c логином и паролем будет отправлено на сервер. Пользователь пройдет процесс аутентификации, при котором клиент и сервер несколько раз обменяются служебными сообщениями. Клиент будет проверен по его логину и паролю в Базе данных и при успешной проверке Сервис AuthService вернет Имя NickName пользователя и сервер вернет клиенту сообщение AuthMessage. Получение такого сообщения с Именем клиента и списком фалов в облаке расценивается, как успешная авторизация клиента и ему будет предоставлена панель управления облаком сервера.
Клиент предоставляет следующий функционал управления:
Add- добавление файлов из ОС пользователя в Облако.Delete- удаление выбранного файла с Облака.Get- копирование файлов с Облака клиенту.
В открывшееся окно с сервера подгрузится актуальная информация: список файлов этого клиента и общая загруженность облака (лимит до 10 Gb).
Спасибо! если дочитали до конца.






