Attended Qt Nagoya Study Group

Although a week has passed, I attended the Qt study group in Nagoya last week.

Last time, I mainly focused on QML, so this time I decided to focus on C++.
I decided to implement a TCP/IP communication feature, which seems like it could be useful later on.

Software Created

The resulting software looks like this.

What it does is simple: when you drag the mouse on the Client-side View, it sends the mouse coordinates to the Server side and displays them on the Server-side View.

The complete project is here:

Code Snippets

There were several sample codes available on the web, so I was able to write it without much confusion.

The socket sending side looks like this:

void TCPClientModel::SendMessage(QString message)
{
    if (tcpClient == nullptr) return;

    QByteArray messageBytes = message.toUtf8();

    int messageSize = messageBytes.length();
    QByteArray sizeBytes;
    QDataStream stream(&sizeBytes, QIODevice::WriteOnly);
    stream << messageSize;

    tcpClient->write(sizeBytes, sizeBytes.length());
    tcpClient->write(messageBytes, messageBytes.length());
    tcpClient->flush();
}

The TCP/IP data part is simply divided into two sections: a size area and a message area. The message follows for the number of bytes stored in the size section.
Writing this size into a byte array was surprisingly tricky. I eventually found QDataStream and decided to use it.

Also, to reduce communication latency, I flush after each send. I couldn’t find how to set the NoDelay option with a quick search…
I’ll look for it properly next time.

Next, the receiving part looks like this:

void TCPClientModel::OnReceived()
{
    while (tcpClient->bytesAvailable() > 0)
    {
        tempBuffer.append(tcpClient->readAll());

        while ((bodySize == 0 && tempBuffer.size() >= 4)
               || (bodySize > 0 && tempBuffer.size() >= bodySize))
        {
            if (bodySize == 0 && tempBuffer.size() >= 4)
            {
                QByteArray numArray = tempBuffer.mid(0, 4);
                QDataStream stream(&numArray, QIODevice::ReadOnly);
                stream >> bodySize;
                tempBuffer.remove(0, 4);
            }

            if (bodySize > 0 && tempBuffer.size() >= bodySize)
            {
                QByteArray bodyArray = tempBuffer.mid(0, bodySize);
                tempBuffer.remove(0, bodySize);
                bodySize = 0;

               emit dataReceived(QString::fromUtf8(bodyArray));
            }
        }
    }
}

Receiving TCP/IP data is more troublesome than sending because sometimes the data might be incomplete, or the current data might be concatenated with the next data packet.

First, I wait until the buffer accumulates 4 bytes to know the size, then remember the message size, and wait until the buffer accumulates that many bytes to reconstruct the message.

However, with this implementation, I suspect that frequent use of QByteArray’s mid and remove might cause many memory reallocations… If the message size increases or the sending interval shortens, more optimization might be necessary.

Summary

I’m satisfied that I was able to create software that integrates QML and C++ with more C++ code than last time.
Code of this level can be written entirely using Qt classes, so it should be multi-platform compatible.
I’d like to create a few more samples like this and then connect them to a small application.