Для роботи зі стеком 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
Добрый день, разрешите вопрос:
во всех примерах работы с QTcpServer его всегда создают в main.cpp, нет ли возможности корректно сохдать его в MainWindow.cpp ?
Просто если перенести код в MainWindow.cpp
то возникает ошибка на клиенте QNativeSocketEngine::write() was not called in QAbstractSocket::ConnectedState
Переменную myserver нужно объявить в заголовочном файле, в противном случае после выполнения конструктора окна эта переменная удаляется, поскольку создана на стеке конструктора.
спасибо, но уже не актуально. Я уже написал классы многопоточного сервера и они переносимы, раскидал их по четырем приложениям, даже не меняя код.
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?