UDP Server-Client Chat in C++/Qt

Arwen picture Arwen · Nov 21, 2013 · Viewed 18.8k times · Source

I'm trying to write a chat program using Qt. It's half completed but it has some problems.

First of all I get an error when I want to send my written message in lineedit to the client. It's a QString, but the writeDatagram only sends a QByteArray. I've googled it and there are some ways for converting QString to QByteArray, but I'm looking for a better solution. I think I should use connectToHost(), but read() and write() don't work.

Second and main problem is that I can't get to send and receive messages continuously! Obviously this one hasn't occurred yet but I know there is something wrong with it because I've tested it on Qt console and it didn't work there too.

I'm new to GUI and Socket programming, therefore I've searched a lot before I post this topic.

Update: My first problem solved, but now the UDP packets don't get send and receive let alone working like a chat application.

Update: I found out what was the problem and I solved it. The code needed two QUdpSocket Objects. I also updated the code. It's now fully functional. If you have other inputs I would love to listen to them, otherwise I've got my answer.

Server:

#include "schat.h"
#include "ui_schat.h"

schat::schat(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::schat)
{
    ui->setupUi(this);
    socketServerc=new QUdpSocket(this);
    socketServer=new QUdpSocket(this);
    socketServer->bind(QHostAddress::LocalHost, 8001);
    connect(socketServer,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));

}

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

void schat::on_sendButton_clicked()
{


    QString word=ui->lineEdit->text();
    ui->textBrowser->append(word);
    QByteArray buffer;
    buffer=word.toUtf8();
    QHostAddress sender;
    quint16 senderPort;
    socketServerc->writeDatagram(buffer.data(), QHostAddress::LocalHost, 7000 );

}

void schat::readPendingDatagrams()
{
    while (socketServer->hasPendingDatagrams()) {
        QByteArray buffer;
        buffer.resize(socketServer->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        socketServer->readDatagram(buffer.data(), buffer.size(),&sender, &senderPort);
        ui->textBrowser->append(buffer.data());

    }

}

Client:

#include "uchat.h"
#include "ui_uchat.h"


uchat::uchat(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::uchat)
{
    ui->setupUi(this);
    clientSocket=new QUdpSocket(this);
    clientSocketc=new QUdpSocket(this);
    clientSocketc->bind(QHostAddress::LocalHost, 7000);
    connect(clientSocketc,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
}

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

void uchat::on_sendButton_clicked()
{
    QString word=ui->lineEdit->text();
    ui->textBrowser->append(word);
    QByteArray buffer;
    buffer.resize(clientSocket->pendingDatagramSize());
    QHostAddress sender;
    quint16 senderPort;
    buffer=word.toUtf8();
    clientSocket->writeDatagram(buffer.data(), QHostAddress::LocalHost, 8001 );
}
void uchat::readPendingDatagrams()
{
    while (clientSocketc->hasPendingDatagrams()) {
        QByteArray buffer;
        buffer.resize(clientSocketc->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        clientSocketc->readDatagram(buffer.data(), buffer.size(),&sender, &senderPort);
        ui->textBrowser->append(buffer.data());

    }

}

Answer

Jeremy Friesner picture Jeremy Friesner · Nov 21, 2013

Converting the QString to a QByteArray is indeed the thing to do. The reason is that UDP packets carry only a series of bytes -- but a QString does not unambiguously represent a sequence of bytes, it represents a sequence of notional characters (a.k.a. QChars). So in order to place that QString into an array of bytes, you have to decide which binary representation you want to encode it as. For example, if you wanted to encode the string using UTF8 encoding (which I would recommend), you'd use QString's toUtf8() method to get the QByteArray representing the UTF8 encoding, and the receiver would use QString's fromUtf8() method to turn the received bytes back into a QString. There are other encodings also (ascii, latin1, local8Bit) but they may not handle internationalization as well as UTF8 does.

As for your second problem ("I can't get to send and receive messages continuously"), you're going to have to be more explicit and descriptive about what happens vs what you expected to happen. I don't know what "continuously" means in this context.