Сбой связи между сокетом Python 3 и QTcpsocket (C++)

Использование библиотеки Qt QTcpsocket и класса сокетов Python 3 в настоящее время. Я уже получил пример клиент / сервер Qt C++ fortune для правильной сборки и запуска. Тем не менее, это для клиента и сервера, которые оба C++. Требование заключается в том, что на сервере работает Python.

# Server.py


import socket

# ...
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("localhost", 45000)
sock.listen(1) # queuing up 1 request for now.

(clientsocket, address) = sock.accept() # waits until client connects.

chunk = clientsocket.recv(1024).decode() # client is now connect
print(chunk) #prints out message from client

msg = "Hello from the server"
msg = str.encode(msg)

# send the message back to the client
clientsocket.sendall(msg)

а также

// Client.h

#ifndef CLIENT_H
#define CLIENT_H
#include <QObject>
#include <QtNetwork/QtNetwork>

class Client : public QObject {
     Q_OBJECT
public:
     Client();
     QTcpSocket *m_socket;
     QHostAddress m_serverAddr = QHostAddress("127.0.0.1");
     quint16 m_serverPort = 45000;
private:
     QDataStream m_dataStream;
     void testConnect();
};
#endif

а также

// client.cpp

Client::Client() {
    m_socket = new QTcpSocket(this);
    m_dataStream.setDevice(m_socket);
    m_dataStream.setVersion(QDataStream::Qt_4_0);
    testConnect();

}

void Client::testConnect() {
        m_socket->abort(); // if m_socket is not already connected, this does nothing
        m_socket->connectToHost(m_serverAddr, m_serverPort);
        if (m_socket->waitForConnected(30000)) {
            qDebug() << "Connected to server...";
            m_socket->write("Hello server from client"); // is received!
            m_socket->waitForBytesWritten();
            m_socket->waitForReadyRead();
            qDebug() << "Reading: " << m_socket->bytesAvailable();
            m_dataStream.startTransaction();
            QString nextFortune;
            m_dataStream >> nextFortune;
            if (!m_dataStream.commitTransaction()) {
                qDebug() << "Read errors have occurred."; // prints when connected to python server. not desired behavior
                m_socket->close();  
                return;              

            }
            // This prints when running the Qt fortune c++ server, but not the python server (above).
            qDebug() << "No read errors occurred during read transactions.";
            qDebug() << nextFortune;
        }

}

В итоге сервер получает сообщение от клиента без проблем, но когда сервер пытается отправить ответ с clientsocket.sendall(msg), m_dataStream.commitTransaction() возвращает ложь Мой первоначальный инстинкт был в том, что кодировка была неправильной на стороне Python. Требуется ли для QDataStream специальная кодировка?

Документация для QDataStream:: commitTransaction ():

bool QDataStream:: commitTransaction ()

Завершает транзакцию чтения. Возвращает true если во время транзакции не было ошибок чтения; в противном случае возвращается false,

Кроме того, после запуска вот вывод клиента C++:

Connected to server...
Reading: 25
Read errors have occurred.

1 ответ

Решение

Когда вы хотите использовать QDataStream с оператором >> Вы должны следовать формату сериализации. Вызов QDataStream.setVersion() выберите конкретный формат.

Я смог найти документацию только для версии 12 (применяется с QDataStream::Qt_4_6 в QDataStream::Qt_4_9) и версия 13 (QDataStream::Qt_5_0).

Версии 12 и 13 имеют одинаковый формат для сериализации QString:

> Если строка нулевая: 0xFFFFFFFF (quint32)

> В противном случае: длина строки в байтах (quint32), за которой следуют данные в UTF-16

Когда вы звоните m_dataStream >> nextFortune он ожидает, что входящие данные будут в формате, описанном выше.

Код в Python для отправки закодирован QString может выглядеть так:

import struct

msg = "Hello from the server".encode("utf-16be")
clientsocket.sendall(struct.pack(">I", len(msg)) + msg)
  • str.encode("utf-16be") - кодирует строку в UTF-16 с порядком байтов
  • struct.pack(">I", len(msg)) - создает 32-разрядное целое число без знака, содержащее длину закодированной строки (I) в порядке с прямым порядком байтов (>)

Все данные, отправляемые клиенту Qt, находятся в порядке с прямым порядком байтов, потому что это неявный порядок, который QDataStream использует.

Я протестировал код с Qt 5.9 и версией сериализации QDataStream::Qt_4_0,

Другие вопросы по тегам