Распределённое приложение для управления коллекцией объектов Vehicle, разделённое на
независимые клиент и сервер, которые обмениваются данными по сети через протокол UDP.
Клиент принимает и разбирает команды пользователя, сервер хранит коллекцию в оперативной памяти,
исполняет команды и сохраняет данные в файл формата CSV.
- Перейти от монолитной консольной программы к архитектуре «клиент — сервер».
- Реализовать сетевое взаимодействие на UDP с использованием как блокирующего
(
DatagramSocketна сервере), так и неблокирующего (DatagramChannel+Selectorна клиенте) API. - Спроектировать прикладной протокол обмена сообщениями (
Request/Response) поверх стандартной сериализации объектов Java. - Разделить ответственность между модулями: общий код, серверная логика, клиентская логика.
- Обеспечить надёжную доставку: повторные попытки на клиенте и сборку больших ответов из частей (чанков).
- Организовать хранение коллекции в файле и её загрузку при старте сервера.
- Покрыть ключевую бизнес-логику модульными тестами (JUnit 5).
Хранимая сущность — Vehicle, объекты лежат в коллекции HashMap<Long, Vehicle> (ключ — key).
| Поле | Тип | Ограничения |
|---|---|---|
id |
long |
> 0, генерируется автоматически, уникален |
name |
String |
не null, не пустая строка |
coordinates |
Coordinates |
не null |
creationDate |
LocalDate |
не null, генерируется автоматически |
enginePower |
Float |
может быть null; если задано — > 0 |
type |
VehicleType |
не null: CAR, SUBMARINE, MOTORCYCLE, CHOPPER |
fuelType |
FuelType |
не null: ELECTRICITY, DIESEL, MANPOWER, NUCLEAR |
Coordinates: x (Double, не null, > -501), y (long).
Vehicle неизменяем (final поля), реализует Comparable (сортировка по мощности → имени → id).
| Категория | Технология |
|---|---|
| Язык | Java 17 |
| Сборка | Maven (многомодульный проект, pom-агрегатор) |
| Сеть | UDP: DatagramSocket (сервер), DatagramChannel + Selector (клиент) |
| Протокол обмена | Сериализация объектов Java (ObjectOutputStream / ObjectInputStream) |
| Хранение | Файл CSV |
| Логирование | Log4j 2 (2.23.1) |
| Тестирование | JUnit 5 (Jupiter 5.10.2) |
| Конфигурация | Переменная окружения VEHICLE_COLLECTION_FILE |
Проект разбит на три Maven-модуля, что обеспечивает чёткое разделение ответственности и исключает зависимость клиента от внутренней логики сервера:
common— модели предметной области, протокол (Request/Response/CommandType) и утилита сериализации. Зависимость, общая для клиента и сервера.server— приём UDP-пакетов, хранение коллекции, диспетчеризация команд, файловый ввод-вывод.client— разбор пользовательского ввода, формирование запросов, отправка по сети и вывод ответов.
- Сервер работает в одном потоке: блокирующий
DatagramSocketс тайм-аутомSO_TIMEOUT = 300 мс, что позволяет в паузах между пакетами опрашивать собственную консоль (командыsave,exit). - Клиент использует неблокирующий
DatagramChannel+Selector. При отсутствии ответа выполняется до 5 повторных попыток с тайм-аутом 2 секунды — приложение устойчиво к потере пакетов и временной недоступности сервера. - Большие ответы (например, вывод всей коллекции) превышают размер одной датаграммы, поэтому
делятся на чанки: каждый пакет несёт заголовок
[всего чанков][индекс], а клиент собирает полное сообщение обратно.
Диспетчеризация команд построена на EnumMap<CommandType, CommandHandler> (CommandRegistry),
что делает добавление новых команд изолированным и предсказуемым.
| Команда | Назначение |
|---|---|
help |
Справка по командам (обрабатывается клиентом) |
info |
Тип коллекции, дата инициализации, размер |
show |
Вывести все элементы (отсортированы) |
insert <key> |
Добавить элемент по ключу |
update <id> |
Обновить элемент по id |
remove_key <key> |
Удалить элемент по ключу |
clear |
Очистить коллекцию |
execute_script <file> |
Выполнить команды из файла (поддержка вложенных скриптов) |
remove_lower |
Удалить все элементы меньше заданного |
replace_if_lower <key> |
Заменить значение, если новое меньше |
remove_lower_key <key> |
Удалить элементы с ключом меньше заданного |
remove_any_by_type <type> |
Удалить один элемент с указанным типом |
filter_greater_than_type <type> |
Элементы с типом больше заданного |
print_field_ascending_fuel_type |
Значения поля fuelType по возрастанию |
save |
Сохранить коллекцию (только на сервере) |
exit |
Завершить работу |
- Идентификаторы и даты создания назначаются на сервере, клиент их не задаёт.
- Коллекция загружается из CSV при старте; при ошибке чтения сервер стартует с пустой коллекцией и пишет предупреждение в лог.
- Сохранение выполняется по команде
save, приexitи через shutdown hook — данные не теряются при штатном завершении. - Все ошибки команд преобразуются в
Response.error(...)и возвращаются клиенту, не роняя сервер.
ITMO_Lab6/
├── README.md
├── data.csv # пример файла коллекции
├── report.docx # отчёт по лабораторной работе
├── Диаграмма классов/ # UML-диаграммы классов (PlantUML + PNG)
│ ├── class-diagram-common.puml / .png
│ ├── class-diagram-server.puml / .png
│ └── class-diagram-client.puml / .png
└── vehicle-collection/ # многомодульный Maven-проект
├── pom.xml # родительский POM (агрегатор)
│
├── common/ # общий модуль (модели + протокол)
│ └── src/main/java/ru/student/vehicle/common/
│ ├── model/ # Vehicle, Coordinates, VehicleType, FuelType, VehicleData
│ ├── protocol/ # Request, Response, CommandType
│ └── net/ # Serialization
│
├── server/ # серверный модуль
│ └── src/main/java/ru/student/vehicle/server/
│ ├── ServerMain.java # точка входа
│ ├── ServerConsole.java # консоль сервера (save / exit)
│ ├── net/ # UdpServer, RequestReader, ResponseSender
│ ├── command/ # CommandRegistry, CommandHandler
│ ├── collection/ # VehicleCollectionManager, VehicleFactory, VehicleIdGenerator
│ └── io/ # CsvVehicleReader, CsvVehicleWriter, CollectionFileResolver
│
└── client/ # клиентский модуль
└── src/main/java/ru/student/vehicle/client/
├── ClientMain.java # точка входа, REPL-цикл
├── net/ # UdpClient
└── console/ # CommandReader, VehicleDataReader, ClientScriptExecutor
- JDK 17+
- Maven 3.8+
cd vehicle-collection
mvn clean packageПеред запуском задаётся путь к файлу коллекции через переменную окружения:
export VEHICLE_COLLECTION_FILE=/абсолютный/путь/к/data.csv
java -jar server/target/server-*.jar # порт по умолчанию 5566
# либо с указанием порта:
java -jar server/target/server-*.jar 5566java -jar client/target/client-*.jar # localhost:5566 по умолчанию
# либо с указанием хоста и порта:
java -jar client/target/client-*.jar localhost 5566После запуска клиента введите help для списка команд.
Модульные тесты (JUnit 5) покрывают ключевую логику:
VehicleCollectionManagerTest— операции над коллекцией (вставка, обновление, фильтрация, удаление).VehicleDataTest— валидация полей модели.SerializationRoundTripTest— корректность сериализации/десериализации протокола (round-trip).
cd vehicle-collection
mvn test- Реализована полноценная архитектура «клиент — сервер» с сетевым обменом по UDP; логика хранения и обработки данных полностью вынесена на сервер, клиент отвечает только за ввод-вывод.
- На практике освоены два подхода к работе с сетью: блокирующий
DatagramSocketи неблокирующийDatagramChannelс мультиплексированием черезSelector. - Решена характерная для UDP проблема — собственный прикладной протокол с сериализацией, повторными попытками и разбиением больших сообщений на чанки обеспечил надёжную доставку.
- Многомодульная структура Maven показала ценность разделения ответственности: общий код вынесен
в
common, а клиент и сервер развиваются независимо. - Продумано сохранение состояния (по команде, при выходе и через shutdown hook) и устойчивость к ошибкам ввода — сервер не падает при некорректных данных или командах.
- Бизнес-логика подкреплена модульными тестами, что упростило проверку корректности при изменениях.