gadget59.ru практика
Сокеты + JSON · Практика · 26 слайдов

Практическая работа: клиент-серверное приложение «Список книг» на сокетах и JSON

Практика: клиент-серверное приложение «Список книг»

Мы изучили сокеты и JSON. Теперь соберём настоящее клиент-серверное приложение: клиент отправляет книги на сервер, сервер их хранит и отдаёт обратно по запросу. Всё общение — по сети через сокеты, в формате JSON.

🔌 Socket 📡 ServerSocket 📄 JSON 🔧 Jackson 📚 Книги
Мы создадим четыре класса: Book (модель книги), BookServer (сервер), BookClient (клиент) и Main (точка входа). Клиент и сервер будут общаться JSON-сообщениями.
Формат: практическая работа, 2 академических часа. Понадобится JDK и Maven (или JAR-файл Jackson).

Цель и задачи

Цель: получить практические навыки работы с сокетами и JSON в Java.

Что мы сделаем

  • 1 Настроим Maven-проект и подключим Jackson.
  • 2 Создадим класс Book с полями title, author, year.
  • 3 Напишем сервер, который принимает JSON и хранит книги в списке.
  • 4 Напишем клиент с меню: добавить книгу, показать все, выйти.
  • 5 Проверим, что данные передаются по сети.
В результате получится мини-приложение, которое работает как настоящий сетевой сервис.

Схема приложения

Вот как устроено наше приложение.

Клиент (BookClient)
↓ JSON через Socket
Сервер (BookServer)
↓ список книг
Хранилище (List<Book>)
КомандаЧто делаетОтвет сервера ADDдобавить книгуOK LISTпоказать все книгиJSON-массив книг EXITвыйтисоединение закрывается
Клиент отправляет команду, сервер её выполняет и отправляет ответ. Простая, но рабочая архитектура.

Шаг 1: создаём Maven-проект

Создадим проект с Maven (система сборки Java, которая сама скачивает библиотеки).

// Структура проекта book-socket-app/ ├── src/ │ └── main/ │ └── java/ │ └── ru/ │ └── gadget59/ │ └── books/ │ ├── Book.java │ ├── BookServer.java │ ├── BookClient.java │ └── Main.java └── pom.xml

В pom.xml добавим зависимость Jackson:

<dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> </dependencies>
Если Maven подключён — Jackson скачается автоматически. В IntelliJ IDEA после сохранения pom.xml нужно нажать «Load Maven Changes».

Шаг 2: класс Book

Класс книги с тремя полями. Он должен иметь конструктор без аргументов и геттеры/сеттеры — это требование Jackson.

package ru.gadget59.books; public class Book { private String title; private String author; private int year; public Book() {} // конструктор без аргументов — нужен Jackson public Book(String title, String author, int year) { this.title = title; this.author = author; this.year = year; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } @Override public String toString() { return title + " — " + author + " (" + year + ")"; } }

Шаг 3: сервер — начало

Сервер слушает порт 8080 и хранит книги в списке.

package ru.gadget59.books; import java.io.*; import java.net.*; import java.util.*; import com.fasterxml.jackson.databind.ObjectMapper; public class BookServer { private static final int PORT = 8080; private static final List<Book> books = new ArrayList<>(); private static final ObjectMapper mapper = new ObjectMapper(); public static void start() { try (ServerSocket serverSocket = new ServerSocket(PORT)) { System.out.println("Сервер запущен на порту " + PORT); while (true) { Socket clientSocket = serverSocket.accept(); System.out.println("Клиент подключился"); handleClient(clientSocket); } } catch (IOException e) { e.printStackTrace(); } } }

Шаг 3: сервер — обработка клиента

Метод handleClient читает команды клиента и отвечает.

private static void handleClient(Socket socket) { try ( BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true) ) { String line; while ((line = in.readLine()) != null) { if (line.equals("LIST")) { out.println(mapper.writeValueAsString(books)); } else if (line.startsWith("ADD ")) { String json = line.substring(4); Book book = mapper.readValue(json, Book.class); books.add(book); out.println("OK"); } else if (line.equals("EXIT")) { break; } } } catch (IOException e) { e.printStackTrace(); } }
Сервер читает строку, разбирает команду и отправляет ответ. Всё общение — построчное, через readLine / println.

Шаг 4: клиент — меню

Клиент подключается к серверу и показывает меню.

package ru.gadget59.books; import java.io.*; import java.net.*; import java.util.Scanner; import com.fasterxml.jackson.databind.ObjectMapper; public class BookClient { public static void start() { try ( Socket socket = new Socket("localhost", 8080); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); Scanner scanner = new Scanner(System.in) ) { ObjectMapper mapper = new ObjectMapper(); while (true) { System.out.println("\n1. Добавить книгу"); System.out.println("2. Показать все"); System.out.println("0. Выход"); System.out.print("Выбор: "); String choice = scanner.nextLine(); if (choice.equals("0")) { out.println("EXIT"); break; } // обработка остальных пунктов — на следующем слайде } } catch (IOException e) { e.printStackTrace(); } } }

Шаг 4: клиент — добавление и список

Обработка пунктов «Добавить книгу» и «Показать все».

if (choice.equals("1")) { System.out.print("Название: "); String title = scanner.nextLine(); System.out.print("Автор: "); String author = scanner.nextLine(); System.out.print("Год: "); int year = Integer.parseInt(scanner.nextLine()); Book book = new Book(title, author, year); String json = mapper.writeValueAsString(book); out.println("ADD " + json); String response = in.readLine(); System.out.println("Ответ сервера: " + response); } else if (choice.equals("2")) { out.println("LIST"); String response = in.readLine(); Book[] books = mapper.readValue(response, Book[].class); if (books.length == 0) { System.out.println("Список пуст"); } else { for (Book b : books) { System.out.println(" " + b); } } }
Сервер возвращает JSON-массив. Мы разбираем его в массив Book[] через mapper.readValue.

Шаг 5: точка входа

Класс Main спрашивает, кем запустить программу — сервером или клиентом.

package ru.gadget59.books; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("1. Запустить сервер"); System.out.println("2. Запустить клиент"); System.out.print("Выбор: "); String choice = scanner.nextLine(); if (choice.equals("1")) { BookServer.start(); } else if (choice.equals("2")) { BookClient.start(); } } }
Сервер нужно запустить первым. Клиент подключается к уже работающему серверу. Если запустить наоборот — клиент получит ошибку подключения.

Проверка работы

Как проверить, что всё работает.

Шаг 1. Запустить сервер

В одном терминале (или в одной вкладке IDE) запустите Main и выберите «1». Увидите:

Сервер запущен на порту 8080

Шаг 2. Запустить клиент

Во втором терминале запустите Main снова и выберите «2».

Шаг 3. Добавить книгу

В меню клиента выберите «1», введите название, автора, год. Увидите:

Ответ сервера: OK

Шаг 4. Показать список

Выберите «2». Сервер вернёт JSON-массив, клиент выведет книги:

Евгений Онегин — Александр Пушкин (1833) Война и мир — Лев Толстой (1869)
Если всё работает — вы написали настоящее клиент-серверное приложение на сокетах с JSON!

Типичные ошибки

1. Порт занят
Ошибка BindException: Address already in use. Значит, сервер уже запущен или порт занят другой программой. Смените порт или закройте лишние процессы.
2. Сервер не запущен
Ошибка ConnectException. Клиент не может подключиться. Запустите сервер первым.
3. Jackson не видит поля
Проверьте, что у Book есть конструктор без аргументов и геттеры/сеттеры для всех полей.
4. Клиент зависает
Вероятно, сервер не отправил ответ. Проверьте, что сервер вызывает out.println после каждой команды.
5. Кракозябры в русских буквах
Возникает при передаче через сокеты. Решение: использовать PrintWriter с UTF-8 и убедиться, что кодировка консоли правильная.
6. Соединение не закрывается
Забыли socket.close() или try-with-resources. Соединение остаётся открытым и «висит».

Задание для расширения

После того как базовое приложение работает, попробуйте его улучшить.

Задание 1. Добавить удаление книги

Добавьте команду DELETE title, которая удаляет книгу по названию. Клиент должен отправлять название, а сервер — удалять книгу из списка.

Задание 2. Поиск по автору

Добавьте команду FIND author, которая возвращает JSON-массив только тех книг, у которых автор совпадает.

Задание 3. Сохранить в файл

При добавлении книги сервер должен дописывать её в файл books.json через Files.writeString.

Задание 4. Несколько клиентов

Сейчас сервер обрабатывает одного клиента за раз. Сделайте так, чтобы каждый клиент обрабатывался в отдельном потоке.

Задания 1 и 2 — обязательны. Задания 3 и 4 — для оценки «отлично».

Дополнительные идеи

Если хотите развивать проект дальше — вот идеи.

🔐
SSLSocket
Шифрование соединения через TLS. Нужно для настоящих паролей.
🧵
Потоки
Каждый клиент обслуживается в своём потоке. Не блокирует других.
📁
База данных
Вместо List использовать JDBC и хранить книги в MS SQL Server.
🌐
REST API
Заменить сокеты на HTTP-сервер через Spring Boot.
Каждая идея — отдельная мини-тема. Когда-нибудь в вашей практике они обязательно пригодятся.

Шпаргалка

Сохраните этот слайд — всё, что нужно для практики.

ЗадачаКод Запустить серверnew ServerSocket(8080) Принять клиентаserverSocket.accept() Подключиться к серверуnew Socket("localhost", 8080) Читать строкуnew BufferedReader(new InputStreamReader(socket.getInputStream())).readLine() Писать строкуnew PrintWriter(socket.getOutputStream(), true).println("text") Объект → JSONmapper.writeValueAsString(book) JSON → объектmapper.readValue(json, Book.class) JSON-массив → массивmapper.readValue(json, Book[].class)
Этих команд достаточно, чтобы повторить практику с нуля.

Итоги практики

Подведём итоги.

  • ✅ Настроили Maven-проект и подключили Jackson.
  • ✅ Создали класс Book с конструктором без аргументов и геттерами.
  • ✅ Написали сервер на ServerSocket, который принимает команды.
  • ✅ Написали клиент с меню и подключением к серверу.
  • ✅ Научились передавать объекты через сокеты в формате JSON.
  • ✅ Разобрали команды ADD, LIST, EXIT.
  • ✅ Поняли, как работает сериализация и десериализация.
  • ✅ Разобрали типичные ошибки и способы их исправления.
Вы прошли путь от «что такое сокет» до работающего сетевого приложения. Это уровень junior-разработчика.

Домашнее задание

Задания для самостоятельной работы.

  1. Повторите практику с нуля — создайте Maven-проект, все четыре класса, запустите сервер и клиент.
  2. Добавьте команду DELETE title — удаление книги по названию.
  3. Добавьте команду FIND author — поиск книг по автору.
  4. Добавьте сохранение книг в файл books.json.
  5. Сделайте так, чтобы сервер обрабатывал несколько клиентов в отдельных потоках.
  6. Добавьте команду COUNT, которая возвращает количество книг на сервере.
Задания 1–3 обязательны. Задания 4–6 — для оценки «отлично».

Как проверить, что всё сделано правильно

Чек-лист для самопроверки.

✅
Maven-проект собирается
Без ошибок.
✅
Jackson подключён
Ошибок «Class not found» нет.
✅
Сервер запускается
Выводит сообщение о порте.
✅
Клиент подключается
Меню отображается.
✅
Добавление работает
Сервер отвечает «OK».
✅
Список отображается
Книги видны в консоли клиента.
Если все пункты отмечены — практика выполнена полностью.

Безопасность в реальных проектах

Наше приложение — учебное. В реальных проектах нужно учитывать безопасность.

  • SSL/TLS. Используйте SSLSocket вместо Socket для шифрования данных.
  • Аутентификация. Клиент должен подтвердить, что он имеет право на запросы.
  • Валидация. Проверяйте данные, которые приходят от клиента (не пустые, корректного типа).
  • Ограничение размера. Ограничивайте размер входящих сообщений, чтобы избежать атак.
  • Логирование. Записывайте все запросы для аудита.
  • Таймауты. Устанавливайте таймаут соединения, чтобы не «висеть» вечно.
В учебных проектах безопасность не критична. Но как только приложение выходит в мир — она становится обязательной.

Что дальше?

Мы закончили блок «Сокеты + JSON». Куда двигаться?

  • JavaFX — современная замена Swing для красивых приложений.
  • HTTP и REST API — как работают сайты и веб-сервисы.
  • Spring Boot — фреймворк для серверной разработки на Java.
  • Базы данных в сети — JDBC + удалённый сервер.
  • Многопоточность и сокеты — обслуживание нескольких клиентов.
Вы освоили базовый уровень сетевого программирования. Дальше — специализация: backend, frontend или мобильная разработка.

Советы для дальнейшей работы

Несколько советов, которые пригодятся в будущем.

📖
Читайте ошибки
Java подробно описывает проблемы. Читайте сообщение полностью.
🧪
Пишите тесты
JUnit — стандарт тестирования. Мы разбирали его в oaip23.
🚀
Пробуйте новое
Каждый проект — это опыт. Не бойтесь экспериментировать.
🤝
Советуйтесь
Программирование — это командная работа. Обсуждайте задачи.
Сетевые приложения — это то, что делает программирование по-настоящему интересным. Вы справились с первой ступенью.

Итоговый чек-лист

Что вы должны уметь после этой практики.

  • ✅ Создавать Maven-проект и подключать Jackson.
  • ✅ Писать класс модели с конструктором без аргументов.
  • ✅ Запускать сервер на ServerSocket и принимать клиентов.
  • ✅ Подключаться клиентом через Socket.
  • ✅ Обмениваться сообщениями через PrintWriter / BufferedReader.
  • ✅ Превращать объект в JSON и обратно.
  • ✅ Работать с JSON-массивом.
  • ✅ Обрабатывать ошибки подключения.
Если вы можете повторить проект без подсказок — вы действительно освоили тему.

Резюме

Короткое резюме практики.

  • Сервер — слушает порт, принимает клиентов, обрабатывает команды.
  • Клиент — подключается к серверу, отправляет команды, выводит ответы.
  • Book — модель данных с сериализацией Jackson.
  • JSON — формат обмена, читаемый и удобный для парсинга.
  • Socket / ServerSocket — основа сетевого общения в Java.
Эти четыре компонента — минимальный набор для любого клиент-серверного приложения.

Что было самым сложным?

Подумайте и ответьте себе:

  • Что было непонятно в самом начале?
  • Что стало понятно после практики?
  • Какая часть больше всего понравилась?
  • Что хотите изучить глубже?
Рефлексия — важная часть обучения. Она помогает понять, что вы действительно усвоили, а что стоит повторить.
Если что-то осталось непонятным — вернитесь к слайдам лекции. Не бойтесь перечитывать.

Проверка результата

Что должно получиться:
  • Maven-проект с четырьмя классами: Book, BookServer, BookClient, Main.
  • При запуске Main выбор «1» — сервер запускается на порту 8080.
  • При выборе «2» — клиент подключается к серверу.
  • Команда «1» в меню клиента — добавление книги.
  • Команда «2» — вывод всех книг.
  • Команда «0» — выход и закрытие соединения.
  • Все данные передаются в формате JSON.
Если всё это работает — практика выполнена на «отлично».

Спасибо за работу!

📚

Клиент-серверное приложение «Список книг» готово!

Вы научились работать с сокетами, JSON и библиотекой Jackson. Это фундамент сетевого программирования на Java.

🔌 Сокеты 📄 JSON 📚 Книги 🚀 сеть