Establishing reliable network communication requires configuring a TCP server capable of managing multiple client connections simultaneously. The Qt Network module provides the necessary classes, specifically QTcpServer and QTcpSocket, to handle low-level socket operations within a GUI application.
Server Architecture Design
The server application acts as a central hub. It listens on a specific port for incoming requests, maintains a list of active sockets, and facilitates message routing between connected users. A timer mechanism is also implemented to monitor the health of active connections.
Header File Configuration
The main window class inherits from QMainWindow and encapsulates the network logic. Key members include the server listener, a list to track client sockets, and a timer for connection validation.
#pragma once
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTimer>
#include "ui_NetworkServerUI.h"
class NetworkServerUI : public QMainWindow
{
Q_OBJECT
public:
explicit NetworkServerUI(QWidget *parent = nullptr);
~NetworkServerUI();
private slots:
void activateListener();
void handleIncomingConnection();
void processIncomingData();
void broadcastMessage(const QByteArray &data);
void verifyClientConnections();
private:
Ui::NetworkServerUIClass ui;
QTcpServer tcpListener;
quint16 listeningPort;
QList<QTcpSocket*> activeClients;
QTimer connectionMonitor;
};
Implementation Details
The source file initializes the UI and binds user actions to network events. When the start button is clicked, the server attempts to bind to the specified address and port.
#include "NetworkServerUI.h"
#include <QMessageBox>
#include <QDebug>
NetworkServerUI::NetworkServerUI(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
// Connect UI button to server activation logic
connect(ui.btnStartServer, &QPushButton::clicked,
this, &NetworkServerUI::activateListener, Qt::UniqueConnection);
}
NetworkServerUI::~NetworkServerUI()
{
// Cleanup handled by parent destructor mostly,
// but sockets should be closed explicitly in production
}
void NetworkServerUI::activateListener()
{
listeningPort = 8080;
// Listen on all available network interfaces
if (!tcpListener.listen(QHostAddress::Any, listeningPort)) {
QMessageBox::critical(nullptr, tr("Error"),
tr("Failed to initialize server on port %1").arg(listeningPort));
return;
}
QMessageBox::information(nullptr, tr("Status"),
tr("Server listening on port %1").arg(listeningPort));
// Bind new connection signal to handler
connect(&tcpListener, &QTcpServer::newConnection,
this, &NetworkServerUI::handleIncomingConnection);
// Start monitoring timer
connectionMonitor.start(5000); // Check every 5 seconds
connect(&connectionMonitor, &QTimer::timeout,
this, &NetworkServerUI::verifyClientConnections);
}
void NetworkServerUI::handleIncomingConnection()
{
QTcpSocket *clientSocket = tcpListener.nextPendingConnection();
if (clientSocket) {
activeClients.append(clientSocket);
// Connect readyRead signal to data processing slot
connect(clientSocket, &QTcpSocket::readyRead,
this, &NetworkServerUI::processIncomingData);
// Optional: Handle disconnection to remove from list
connect(clientSocket, &QTcpSocket::disconnected, [this, clientSocket]() {
activeClients.removeAll(clientSocket);
clientSocket->deleteLater();
});
}
}
void NetworkServerUI::processIncomingData()
{
QTcpSocket *senderSocket = qobject_cast<QTcpSocket*>(sender());
if (!senderSocket) return;
QByteArray data = senderSocket->readAll();
// Logic to echo or forward data would go here
qDebug() << "Received data:" << data;
// Example: Broadcast to all other clients
// broadcastMessage(data);
}
Connection Management
Maintaining the list of active sockets allows the server to iterate through clients when distributing messages. The activeClients list stores pointers to established connections. When data arrives, the readyRead signal trgigers the processing slot, wich retrieves the payload using readAll().
For robustness, a QTimer periodically checks the status of sockets in the list. If a socket is no longer writable or encounters an error, it should be removed from the list to prevent sending data to dead connections. The lambda function connected to the disconnected signal ensures that the server cleans up resources immediately when a client drops off.