Evgenii Legotckoi
Evgenii Legotckoi08 грудня 2015 р. 21: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 хостинг.

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

ИВ
  • 16 березня 2021 р. 00: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 р. 16:36

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

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

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

e
  • 16 серпня 2021 р. 22: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
Г

C++ - Тест 001. Первая программа и типы данных

  • Результат:66бали,
  • Рейтинг балів-1
t

C++ - Тест 001. Первая программа и типы данных

  • Результат:33бали,
  • Рейтинг балів-10
t

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

  • Результат:52бали,
  • Рейтинг балів-4
Останні коментарі
G
GoattRock03 вересня 2024 р. 20:50
Як скопіювати файли в Linux Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
ВР
Влад Русоков02 серпня 2024 р. 08:47
Як скопіювати файли в Linux Screenshot_20240802-065123.png
d
dblas505 липня 2024 р. 18:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr09 лютого 2024 р. 02:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 09:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi24 червня 2024 р. 22:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
Fynjy22 липня 2024 р. 11:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCT25 червня 2024 р. 08:00
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCT05 травня 2024 р. 12:46
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii Legotckoi02 травня 2024 р. 21:07
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

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