Лаб. работа “Средства языка для организации работы в сети. Основные классы и интерфейсы реализации сетевого взаимодействия”
Цель работы
Изучить основные классы сетевого модуля Qt — QTcpServer и QTcpSocket. Освоить процесс установления TCP-соединения, а также асинхронную отправку и получение данных с помощью механизма сигналов и слотов (readyRead(), write()).
Теоретические сведения
Сетевой модуль Qt
Для работы с сетью в Qt используется модуль Qt Network. Основные классы:
| Класс | Назначение |
|---|---|
QTcpServer |
TCP-сервер, принимающий входящие подключения |
QTcpSocket |
TCP-сокет для установки соединения и обмена данными |
QUdpSocket |
UDP-сокет для отправки датаграмм |
QHostAddress |
IP-адрес |
QNetworkInterface |
Информация о сетевых интерфейсах |
Конфигурация CMake
QTcpServer — создание сервера
Обработка нового подключения
void MyClass::onNewConnection() {
QTcpSocket* client = server->nextPendingConnection();
connect(client, &QTcpSocket::readyRead, this, &MyClass::onReadyRead);
connect(client, &QTcpSocket::disconnected, client, &QTcpSocket::deleteLater);
qDebug() << "Новое подключение:" << client->peerAddress().toString();
}QTcpSocket — отправка и получение данных
// Отправка данных
void sendData(QTcpSocket* socket, const QString& data) {
socket->write(data.toUtf8());
socket->flush();
}
// Приём данных (асинхронный, через сигнал)
void MyClass::onReadyRead() {
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
QByteArray data = socket->readAll();
qDebug() << "Получено:" << data;
}QTcpSocket — подключение клиента
QTcpSocket* socket = new QTcpSocket(this);
connect(socket, &QTcpSocket::connected, this, &MyClass::onConnected);
connect(socket, &QTcpSocket::readyRead, this, &MyClass::onReadyRead);
connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::errorOccurred),
this, &MyClass::onError);
socket->connectToHost("127.0.0.1", 8080);Механизм сигналов и слотов
Сигналы и слоты — механизм Qt для асинхронного взаимодействия между объектами:
Задание для выполнения
Разработать клиент-серверное приложение «Эхо-сервер» с использованием QTcpServer и QTcpSocket. Сервер принимает текстовые сообщения от клиента и возвращает их обратно (эхо). Поддерживается множество одновременных подключений.
Требования к программе
Сервер (консольное приложение):
- Создать класс
EchoServer(наследникQObject):- поле:
QTcpServer* server - метод
start(int port)— запуск сервера на указанном порту, вывод:[Server] Запущен на порту <port> - слот
onNewConnection()— принятие подключения, подключение сигналовreadyReadиdisconnected, вывод информации о подключившемся клиенте (IP и порт) - слот
onReadyRead()— чтение данных от клиента, вывод:[<IP>:<порт>] <сообщение>, отправка эхо-ответа клиенту (префиксECHO:) - слот
onClientDisconnected()— вывод информации об отключении клиента
- поле:
- Сервер должен поддерживать несколько одновременных клиентов (каждое подключение — отдельный
QTcpSocket).
Клиент (консольное приложение):
- Создать класс
EchoClient(наследникQObject):- поле:
QTcpSocket* socket - метод
connectToServer(const QString& host, int port)— подключение к серверу - метод
send(const QString& message)— отправка сообщения - слот
onConnected()— вывод:[OK] Подключен к серверу - слот
onReadyRead()— вывод полученного эхо-ответа:[ECHO] <сообщение> - слот
onDisconnected()— вывод:[INFO] Соединение закрыто - слот
onError()— вывод ошибки
- поле:
- В функции
main()клиента:- Подключиться к серверу
- В цикле
whileсчитывать строки с клавиатуры и отправлять их серверу - Команда
quit— отключение от сервера
Пример ожидаемого вывода
Сервер:
[Server] Запущен на порту 8080
[+] Клиент подключен: 127.0.0.1:54321
[127.0.0.1:54321] Hello, Server!
[127.0.0.1:54321] How are you?
[-] Клиент отключен: 127.0.0.1:54321
[+] Клиент подключен: 127.0.0.1:54322
[127.0.0.1:54322] Another client here
[-] Клиент отключен: 127.0.0.1:54322
Клиент 1:
[OK] Подключен к серверу
> Hello, Server!
[ECHO] ECHO: Hello, Server!
> How are you?
[ECHO] ECHO: How are you?
> quit
[INFO] Соединение закрыто
Индивидуальные задания
Для каждого варианта разработать два консольных приложения на C++ с использованием Qt6 (QTcpServer, QTcpSocket, сигналы/слоты). Сервер поддерживает несколько одновременных клиентов. Обмен данными — текстовые команды по TCP (каждая команда завершается \n).
Вариант 1. Сервер времени
Протокол: команда TIME → ответ TIME:YYYY-MM-DD HH:MM:SS, команда DATE → ответ DATE:YYYY-MM-DD, команда ECHO:текст → ответ ECHO:текст. Сервер: TimeServer — QTcpServer, при получении команды возвращает соответствующий ответ. Поддержка нескольких клиентов. Клиент: TimeClient — QTcpSocket, текстовое меню: 1 — запросить время, 2 — запросить дату, 3 — эхо-сообщение, 0 — выход. Команда quit — отключение.
Вариант 2. Сетевой калькулятор
Протокол: CALC:операнд1 оператор операнд2 → RESULT: значение или ERROR: описание.
Пример: CALC:10 + 5 → RESULT: 15.
Сервер: CalcServer. Клиент: CalcClient — ввод выражений в формате операнд1 оператор операнд2.
Вариант 3. Сервер-переворотчик
Протокол: - REVERSE:текст → RESULT: перевёрнутый_текст - UPPER:текст → RESULT: ЗАГЛАВНЫЕ - LOWER:текст → RESULT: строчные
Сервер: TextServer. Клиент: TextClient — консольное меню (1 — перевернуть, 2 — в верхний регистр, 3 — в нижний регистр, 0 — выход).
Вариант 4. Справочник DNS (имитация)
Протокол: - LOOKUP:домен → IP: адрес или NOT_FOUND - ADD:домен:IP → OK или ERROR: уже_существует - LIST → нумерованный список записей (домен → IP)
Сервер: DNSServer — хранит std::map<QString, QString> с начальным набором записей. Клиент: DNSClient — консольное меню (1 — поиск, 2 — добавить, 3 — список, 0 — выход).
Вариант 5. TO-DO список
Протокол: - ADD:задача → OK: номер_задачи - DONE:номер → OK или ERROR: неверный_номер - LIST → нумерованный список задач - CLEAR → OK
Сервер: TodoServer — хранит список задач для каждого клиента отдельно. Клиент: TodoClient — консольное меню (1 — добавить, 2 — выполнить, 3 — список, 4 — очистить, 0 — выход).
Вариант 6. Сервер погоды (имитация)
Протокол: - WEATHER:город → TEMP: значение HUMIDITY: значение WIND: значение или ERROR: город_не_найден - CITIES → список доступных городов через запятую
Сервер: WeatherServer — хранит предзаполненные данные для 5–7 городов. Клиент: WeatherClient — консольное меню (1 — погода города, 2 — список городов, 0 — выход).
Вариант 7. Сервер конвертации валют
Протокол: - CONVERT:сумма:из:в → RESULT: значение или ERROR: неизвестная_валюта - RATES → список курсов (валюта → курс к базовой)
Сервер: CurrencyServer — хранит std::map<QString, double> курсов (USD, EUR, RUB, CNY и др.). Клиент: CurrencyClient — консольное меню (1 — конвертировать, 2 — список курсов, 0 — выход).
Вариант 8. Сервер генерации паролей
Протокол: - PASS:длина → PASSWORD: пароль (буквы + цифры) - PASS:длина:тип → PASSWORD: пароль, где тип: alpha / num / all (буквы+цифры+символы)
Сервер: PassServer. Клиент: PassClient — запрос длины и типа, вывод сгенерированного пароля.
Вариант 9. Телефонный справочник
Протокол: - FIND:имя → PHONE: номер или NOT_FOUND - ADD:имя:телефон → OK или ERROR: уже_существует - ALL → нумерованный список всех записей - DELETE:имя → OK или ERROR: не_найден
Сервер: PhoneServer — хранит std::map<QString, QString> с начальными записями. Клиент: PhoneClient — консольное меню (1 — найти, 2 — добавить, 3 — все записи, 4 — удалить, 0 — выход).
Вариант 10. Сервер логирования
Протокол: - LOG:уровень:сообщение → OK (уровень: INFO, WARN, ERROR) - GETLOG → содержимое журнала (все записи, по одной на строку) - CLEARLOG → OK
Сервер: LogServer — сохраняет записи в QVector<QString> и дополнительно в файл server.log. Клиент: LogClient — консольное меню (1 — записать, 2 — получить журнал, 3 — очистить, 0 — выход).
Вариант 11. Хранилище ключей-значений
Протокол: - SET:ключ:значение → OK - GET:ключ → VALUE: значение или NOT_FOUND - DEL:ключ → OK или ERROR: не_найден - KEYS → список ключей через запятую
Сервер: KVServer — хранит std::map<QString, QString>. Клиент: KVClient — консольное меню (1 — задать, 2 — получить, 3 — удалить, 4 — список ключей, 0 — выход).
Вариант 12. Сервер анаграмм
Протокол: ANAGRAM:слово → RESULT: анаграмма1, анаграмма2, ... или RESULT: нет_анаграмм.
Сервер: AnagramServer — содержит встроенный словарь слов (до 6 символов), находит все анаграммы. Клиент: AnagramClient — ввод слова, вывод найденных анаграмм.
Вариант 13. Сервер голосования
Протокол: - VOTE:номер → OK или ERROR: неверный_вариант (варианты 1–4) - RESULTS → RESULTS: вариант1:голоса, вариант2:голоса, вариант3:голоса, вариант4:голоса
Сервер: VoteServer — один опрос с 4 вариантами ответа, подсчёт голосов (QVector<int>). Клиент: VoteClient — отображение вариантов, ввод номера, просмотр результатов.
Вариант 14. Сервер системной информации
Протокол: - INFO → HOST: имя OS: система CPUS: число RAM: МБ - UPTIME → UPTIME: секунды - PING → PONG: timestamp
Сервер: InfoServer — использует QSysInfo, QHostInfo. Клиент: InfoClient — консольное меню (1 — информация, 2 — аптайм, 3 — пинг, 0 — выход).
Вариант 15. Генератор случайных чисел
Протокол: - RAND:min:max → RESULT: число - RANDS:min:max:количество → RESULTS: число1, число2, ...
Сервер: RandServer — использует QRandomGenerator. Клиент: RandClient — ввод диапазона и количества, вывод результатов.
Вариант 16. Сервер чата (многоклиентский)
Протокол: - LOGIN:имя → OK: имя или ERROR: имя_занято - MSG:текст → рассылка всем клиентам в формате [имя] текст - USERS → USERS: имя1, имя2, ...
Сервер: ChatServer — хранит список подключённых клиентов с именами, рассылает сообщения всем (QList<QTcpSocket*>). Клиент: ChatClient — отдельный поток или QSocketNotifier для приёма сообщений, ввод текста в основном потоке.
Вариант 17. Сервер файловых операций (имитация)
Протокол: - TOUCH:имя → OK или ERROR: уже_существует - LS → список файлов через запятую - RM:имя → OK или ERROR: не_найден - SIZE:имя → SIZE: байты или ERROR: не_найден
Сервер: FileServer — файловая система в памяти (std::map<QString, QByteArray>, размер — длина содержимого). Клиент: FileClient — консольное меню (1 — создать, 2 — список, 3 — удалить, 4 — размер, 0 — выход).
Вариант 18. Сервер конвертации чисел
Протокол: - BIN:число → RESULT: двоичное_представление - OCT:число → RESULT: восьмеричное_представление - HEX:число → RESULT: шестнадцатеричное_представление
Пример: BIN:42 → RESULT: 101010.
Сервер: ConvServer. Клиент: ConvClient — консольное меню (1 — BIN, 2 — OCT, 3 — HEX, 0 — выход).
Вариант 19. Сервер статистики текста
Протокол: STAT:текст → CHARS: n WORDS: n LINES: n.
Пример: STAT:Hello world → CHARS: 11 WORDS: 2 LINES: 1.
Сервер: StatServer — подсчитывает символы (без пробелов), слова и строки. Клиент: StatClient — ввод многострочного текста (пустая строка — отправка), вывод статистики.
Вариант 20. Сервер анаграмм
Протокол: ANAGRAM:слово → RESULT:анаграмма1,анаграмма2,... (все перестановки, слова до 6 символов), WORDS:длина → RESULT:слово1,слово2,... (случайные слова заданной длины), VALIDATE:слово → OK или NOT_IN_DICT. Сервер: AnagramServer — QTcpServer, хранит словарь (setAnagramClient — QTcpSocket, меню: 1 — найти анаграммы, 2 — случайные слова, 3 — проверить слово, 0 — выход.
Порядок выполнения
- Создать проект C++ в Qt Creator (CMake), подключить модуль
Qt6::CoreиQt6::Network. - Реализовать класс
EchoServerс поддержкой нескольких клиентов. - Реализовать класс
EchoClientс консольным вводом. - Запустить сервер, затем запустить два экземпляра клиента в разных терминалах.
- Убедиться, что оба клиента получают свои эхо-ответы, сервер корректно отображает все подключения и отключения.
- Скомпилировать, сохранить скриншоты (сервер + оба клиента).
Контрольные вопросы
- Какие классы модуля Qt Network использованы в работе? Каково их назначение?
- Какое преимущество даёт асинхронная работа с сокетами через сигналы и слоты по сравнению с синхронными вызовами?
- Как работает сигнал
QTcpServer::newConnection? Что такоеnextPendingConnection()? - Почему необходимо вызывать
deleteLater()при отключении клиента? - Как метод
qobject_cast<QTcpSocket*>(sender())позволяет определить, от какого клиента пришли данные? - В чём разница между
QTcpSocket::write()иQTcpSocket::flush()? - Что произойдёт, если клиент отправит данные быстрее, чем сервер успевает их обрабатывать?
- Как получить IP-адрес и порт подключённого клиента через
QTcpSocket?
Содержание отчёта
- Тема, цель и задание лабораторной работы.
- Схема взаимодействия: сервер ↔︎ клиенты (с указанием сигналов и слотов).
- Текст программы (сервер и клиент) с комментариями.
- Скриншоты: сервер с двумя подключёнными клиентами, обмен сообщениями.
- Ответы на контрольные вопросы.
