Evgenii Legotckoi
Evgenii Legotckoi08 грудня 2015 р. 10:20

Qt/C++ - Урок 034. Сервер Echo на основі QTcpServer

Для роботи зі стеком TCP/IP Qt надає класи QTcpServer, QTcpSocket, і QUdpSocket. Для першого знайомства з роботою локальної мережі напишемо Echo Сервер . Завдання відлуння сервера відправляти назад до відправника отримані від нього дані, як це робить відлуння з людським голосом. Для підключення до сервера використовуватиметься telnet.

> TELNET (англ. TERminaL NETwork) — мережевий протокол для реалізації текстового інтерфейсу через мережу (у сучасній формі — за допомогою транспорту TCP). Назва «telnet» мають також деякі утиліти, що реалізують клієнтську частину протоколу.
>
>

У пропонованій програмі об'єкт класу QTcpServer слухатиме один із портів стека протоколів TCP/IP від усіх хостів у мережі. Прослуховування порту встановлюється методом listen() із зазначенням специфікованої IP-адреси або діапазону IP-адрес, а також порту прослуховування.

Коли відбувається підключення клієнта до порту, викликається сигнал newConnection() , який буде підключений до слота slotNewConnection(), у цьому слоті буде ініційовано підключення клієнта як об'єкт QTcpSocket на стороні сервера за допомогою методу nextPendingConnection(), який повертає покажчик на об'єкт QTcpSocket.

До нового сокету буде підключено два слоти. Перший слот slotServerRead() буде підключений до сигналу readyRead від сокету і буде викликатись у тому випадку, якщо на сокет прийшли дані, які готові до читання. Другий слот slotClientDisconnected() підключений до сигналу disconnected() , який викликається у разі, коли клієнт відключився від сервера і потрібно закрити з'єднання з боку сервера.

Структура проекту для роботи з QTcpServer

Буде створено консольну програму, отже класів на кшталт MainWindow у додатку використано не буде.

  • EchoServer.pro - профайл проекту;
  • main.cpp - основний файл вихідних кодів;
  • mytcpserver.h - заголовний файл сервера;
  • mytcpserver.cpp - файл вихідних кодів сервера;

EchoServer.pro

У цьому файлі необхідно додати модуль Qt для роботи з мережею.

QT += network

main.cpp

Все, що потрібно зробити в даному файлі, це підключити файл заголовка сервера і створити екземпляр сервера.

#include <QCoreApplication>
#include "mytcpserver.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MyTcpServer server;

    return a.exec();
}

mytcpserver.h

Цей клас є обгорткою для роботи з QTcpServer і успадкований від QObject для застосування сигналів та слотів .

#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H

#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>

class MyTcpServer : public QObject
{
    Q_OBJECT
public:
    explicit MyTcpServer(QObject *parent = 0);

public slots:
    void slotNewConnection();
    void slotServerRead();
    void slotClientDisconnected();

private:
    QTcpServer * mTcpServer;
    QTcpSocket * mTcpSocket;
};

#endif // MYTCPSERVER_H

mytcpserver.cpp

#include "mytcpserver.h"
#include <QDebug>
#include <QCoreApplication>

MyTcpServer::MyTcpServer(QObject *parent) : QObject(parent)
{
    mTcpServer = new QTcpServer(this);

    connect(mTcpServer, &QTcpServer::newConnection, this, &MyTcpServer::slotNewConnection);

    if(!mTcpServer->listen(QHostAddress::Any, 6000)){
        qDebug() << "server is not started";
    } else {
        qDebug() << "server is started";
    }
}

void MyTcpServer::slotNewConnection()
{
    mTcpSocket = mTcpServer->nextPendingConnection();

    mTcpSocket->write("Hello, World!!! I am echo server!\r\n");

    connect(mTcpSocket, &QTcpSocket::readyRead, this, &MyTcpServer::slotServerRead);
    connect(mTcpSocket, &QTcpSocket::disconnected, this, &MyTcpServer::slotClientDisconnected);
}

void MyTcpServer::slotServerRead()
{
    while(mTcpSocket->bytesAvailable()>0)
    {
        QByteArray array = mTcpSocket->readAll();

        mTcpSocket->write(array);
    }
}

void MyTcpServer::slotClientDisconnected()
{
    mTcpSocket->close();
}

Робота з Echo Server

Після того, як Ви зберете проект і у Вас запуститься консольна програма, скористайтесь будь-яким програмним забезпеченням, яке підтримує telnet, наприклад Putty, та підключіться на налаштований порт. Спробуйте надіслати дані сервер, щоб переконатися, що він їх поверне. У деяких випадках цього може не статися або Ви взагалі не зможете підключитися, тоді відключіть **FireWall, часто проблема ховається саме в ньому.

Демонстрація роботи програми з додатковими коментарями представлена у відеоуроці.

Посилання на завантаження проекту в zip-архіві: echoserver.zip

Відеоурок

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

ИВ
  • 15 березня 2021 р. 14:46
  • (відредаговано)

Добрый день, разрешите вопрос:
во всех примерах работы с QTcpServer его всегда создают в main.cpp, нет ли возможности корректно сохдать его в MainWindow.cpp ?
Просто если перенести код в MainWindow.cpp

#include "myserver.h"

MainWindow::MainWindow( QWidget *parent): QMainWindow(parent) , ui(new Ui::MainWindow)
{
    myserver Server;
    Server.startServer();
    ui->setupUi(this);

то возникает ошибка на клиенте QNativeSocketEngine::write() was not called in QAbstractSocket::ConnectedState

Evgenii Legotckoi
  • 02 липня 2021 р. 06:36

Переменную myserver нужно объявить в заголовочном файле, в противном случае после выполнения конструктора окна эта переменная удаляется, поскольку создана на стеке конструктора.

ИВ
  • 02 липня 2021 р. 06:51

спасибо, но уже не актуально. Я уже написал классы многопоточного сервера и они переносимы, раскидал их по четырем приложениям, даже не меняя код.

e
  • 16 серпня 2021 р. 12:43

Hi, great post.

If I were to reimplement QTcpServer for the purposes of SSL, shouldn't incomingConnection(int socket) just be automatically called after a connection occurs?

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
Ua

Qt - Тест 001. Сигналы и слоты

  • Результат:84бали,
  • Рейтинг балів4
Ua

Qt - Тест 001. Сигналы и слоты

  • Результат:42бали,
  • Рейтинг балів-8
ОК

Qt - Тест 001. Сигналы и слоты

  • Результат:47бали,
  • Рейтинг балів-6
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 11:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 14:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 08:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 07:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 11:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Дмитрий
Дмитрий03 лютого 2025 р. 06:24
Создание deb-пакета. Как создать ярлык на рабочем столе после установки собственного deb-пакета? Всем привет. Сделал свой deb-пакет с программой. Всё устанавливается и работает. Ставлю по пути /usr/bin/my_application. Как для пользователя при установке пакета сразу создать ярлык на раб…
NW
Nayo Wai30 січня 2025 р. 09:22
не запускается компьютер!!! Не запускается компьютер (точнее работает блок , но сам монитор вообще жесть)В общем я ничего с интернета не скачивала в последнее время. На компе никаких левых пр…
n
nkly03 січня 2025 р. 02:52
Нужно запретить перемещение только некоторых итемов, остальные перемещать можно. Вопрос решен. Узнать QModelIndex элемента на который мы перетаскиваем другой элемент, можно с помощью функции indexAt(event->position().toPoint()) представления QTreeViev вызываемой в переопр…
M
Marsel16 серпня 2023 р. 14:26
OAuth2.0 через VK, получение email Спасибо большое за помощь и простите за то что отнял время своей невнимательностью.
Evgenii Legotckoi
Evgenii Legotckoi24 червня 2024 р. 15:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.

Слідкуйте за нами в соціальних мережах