Для работы со стеком 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?