Penggunaan Slot Socket Port dengan Qt: Membangun Server Sederhana

Penggunaan Slot Socket Port dengan Qt: Membangun Server Sederhana

Dalam artikel ini, kita akan membahas penggunaan slot socket port dengan Qt untuk membuat server sederhana. Kita akan menggunakan kelas QTcpServer dan QTcpSocket dari Qt Networking module untuk menerima dan mengirim data melalui jaringan.

Membangun Server

Pertama, kita akan membuat kelas Server yang menginherit dari QMainWindow. Kelas ini akan memiliki beberapa slot, yaitu newConnection(), disconnected(), dan readyRead(). Slot-slot tersebut akan digunakan untuk menghandle event yang terkait dengan socket.

Kode-kode berikut adalah implementasi kelas Server:

// Server.h
#ifndef SERVER_H
#define SERVER_H

#include <QMainWindow>
#include <QtCore>
#include <QtNetwork>
#include <QString>

namespace Ui {
class Server;
}

class Server : public QMainWindow {
 Q_OBJECT
public:
 explicit Server(QWidget *parent = nullptr);
 ~Server();

signals:
 void dataReceived(QByteArray);

private slots:
 void newConnection();
 void disconnected();
 void readyRead();

private:
 Ui::Server *ui;
 QTcpServer *server;
 QHash<QTcpSocket*, QByteArray*> buffers; // We need a buffer to store data until block has completely received
 QHash<QTcpSocket*, qint32*> sizes; // We need to store the size to verify if a block has received completely
};

#endif // SERVER_H

// Server.cpp
#include "server.h"
#include "ui_server.h"

static inline qint32 ArrayToInt(QByteArray source);

Server::Server(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::Server)
{
 ui->setupUi(this);
 server = new QTcpServer(this);
 connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));

 QString socket_data;
 socket_data.sprintf("Listening: %s\n", server->listen(QHostAddress::Any, 1024) ? "true" : "false");
 ui->textBrowser->insertPlainText(socket_data);
}

Server::~Server()
{
 delete ui;
}

void Server::newConnection()
{
 while (server->hasPendingConnections())
 {
 QTcpSocket *socket = server->nextPendingConnection();
 connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
 connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
 QByteArray *buffer = new QByteArray();
 qint32 *s = new qint32(0);
 buffers.insert(socket, buffer);
 sizes.insert(socket, s);
 }
}

void Server::disconnected()
{
 QTcpSocket *socket = static_cast<QTcpSocket*>(sender());
 QByteArray *buffer = buffers.value(socket);
 qint32 *s = sizes.value(socket);
 socket->deleteLater();
 delete buffer;
 delete s;
}

void Server::readyRead()
{
 QTcpSocket *socket = static_cast<QTcpSocket*>(sender());
 QByteArray *buffer = buffers.value(socket);
 qint32 *s = sizes.value(socket);
 qint32 size = *s;
 while (socket->bytesAvailable() > 0)
 {
 buffer->append(socket->readAll());
 while ((size == 0 && buffer->size() >= 4) || (size > 0 && buffer->size() >= size)) // While can process data, process it
 {
 if (size == 0 && buffer->size() >= 4) // If size of data has received completely, then store it on our global variable
 {
 size = ArrayToInt(buffer->mid(0, 4));
 *s = size;
 buffer->remove(0, 4);
 }

 if (size > 0 && buffer->size() >= size) // If data has received completely, then emit our SIGNAL with the data
 {
 ui->textBrowser->insertPlainText(QString(buffer->data()));
 QByteArray data = buffer->mid(0, size);
 buffer->remove(0, size);
 size = 0;
 *s = size;
 emit dataReceived(data);
 }
 }
 }
}

qint32 ArrayToInt(QByteArray source)
{
 qint32 temp;
 QDataStream data(&source, QIODevice::ReadWrite);
 data >> temp;
 return temp;
}

Kelas Server memiliki beberapa fungsi:

  • newConnection(): Menghandle event ketika sebuah socket baru terhubung.
  • disconnected(): Menghandle event ketika sebuah socket terputus.
  • readyRead(): Menghandle event ketika data baru diterima dari sebuah socket.

Fungsi readyRead() akan mengumpulkan data yang diterima dari socket dan mengolahnya. Jika data telah lengkap, maka fungsi ini akan memungutkannya sebagai SIGNAL dataReceived.

Menggunakan Server

Untuk menggunakan server ini, kita perlu membuat sebuah aplikasi Qt yang memiliki slot untuk menerima sinyal dataReceived. Misalnya, kita dapat membuat sebuah kelas Client yang memiliki fungsi receiveData() yang akan dipanggil ketika data diterima dari server.

Kode-kode berikut adalah implementasi kelas Client:

// Client.cpp
#include "client.h"

Client::Client(QObject *parent) : QObject(parent)
{
 // Membuat sebuah socket dan terhubung ke server
 socket = new QTcpSocket(this);
 connect(socket, SIGNAL(connected()), this, SLOT(readyRead()));
}

void Client::receiveData(QByteArray data)
{
 // Mengolah data yang diterima dari server
 // ...
}

Dalam kelas Client, kita membuat sebuah socket dan terhubung ke server. Ketika data diterima dari server, maka fungsi receiveData() akan dipanggil.

Penggunaan Server

Untuk menggunakan server ini, kita perlu membuat sebuah aplikasi Qt yang memiliki slot untuk menerima sinyal dataReceived. Misalnya, kita dapat membuat sebuah kelas Main yang memiliki fungsi startServer() yang akan memulai server.

Kode-kode berikut adalah implementasi kelas Main:

// Main.cpp
#include "main.h"

int main(int argc, char *argv[])
{
 // Membuat sebuah aplikasi Qt
 QApplication app(argc, argv);

 // Membuat sebuah instance dari kelas Server
 server = new Server();

 // Memulai server
 server->startServer();

 return app.exec();
}

Dalam kelas Main, kita membuat sebuah aplikasi Qt dan memulai server. Server ini akan berjalan di latar belakang dan menghandle event yang terkait dengan socket.

Dalam artikel ini, kita telah membahas penggunaan slot socket port dengan Qt untuk membuat server sederhana. Kita dapat menggunakan server ini sebagai dasar untuk membuat aplikasi Qt yang lebih kompleks.