Search code examples
pythonc++qtsocketsqdatastream

What is the proper way to exchange data between QTcpSocket and python socket?


I am sending .jpg images from Qt client to python server. Qt client sends as follows:

void Sender::sendToServer(QByteArray imageData)
{
    QDataStream stream(serverSocket);
    int t = imageData.size();
    stream << t;
    stream << imageData;
    serverSocket->waitForBytesWritten(-1);
    qDebug() << "Frame size:" << imageData.size();
}

And the server is:

unpacker = struct.Struct('!i')
conn, addr = s.accept()
bool = True
data = b''
while True:
    while len(data) < 4:
        try:
            data += conn.recv(100)
        except:
            break
    img_size = unpacker.unpack(data[:4])[0]
    print('size: ', img_size)
    print('Data: ',data)
    print('Image: ',data[:8])  # deleting preceding 8 bytes
    # image processing

The output is:

//Client:
Frame size: 49993

//Server:
size: 49993
Data: b'\x00\x00\xc3\r\x00\x00\xc3\r\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01...
Image: b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00...

In the output, .jpg file starts from '\xff\xd8'. As C++ int is 4 byte, the server expects "{4 byte}\xff\xd8...". However, preceding bytes are always of different size. Sometimes it's 8 bytes, but sometimes even different (such as 6 or 9 bytes). I could not figure out the reason behind it. What is the problem here?

Platform: win7, Qt 5.9.1, Python 3.4.


Edit

Following @Frank's answer, I changed the code as follows and everything works fine:

Qt client send method:

void Sender::sendToServer(QByteArray imageData)
{
    QDataStream stream(serverSocket);
    QString size = QString::number(data.size());
    QString size_8_byte = size.rightJustified(8, ' ');  // add spaces to make it exactly 8 bytes
    imageData.prepend(size_8_byte.toUtf8());
    stream.writeRawData((char*)(imageData.data()), imageData.size());

    serverSocket->waitForBytesWritten(-1);
}

Python server:

unpacker = struct.Struct('8s')
conn, addr = s.accept()
data = b''
bool = True
while True:
    while len(data) < 8:
        try:
            data += conn.recv(100)
        except:
            break
    img_size = unpacker.unpack(data[:8])[0]
    img_size = int(img_size.decode("utf-8").strip())  #remove spaces and convert to int
    data = data[8:]     #correct data
    #image processing

Solution

  • QDataStream is not a simple binary dumper, it formats the data in some internally defined way. This helps with stuff like endianness correction and the like,

    However, there is a very simple fix available to you: QDataStream provides the writeRawData() function, which bypasses all formatting operations.

    Simply change your output operations to using it and you should be good to go.