Python 3 套接字和 QTcpsocket (c++) 之间的通信失败

Communication fails between Python 3 socket and QTcpsocket (c++)

目前正在使用 Qt 的 QTcpsocket 库和 python 3 的套接字 class。我已经得到了 Qt 的 c++ fortune 客户端/服务器示例来构建和 运行 正确。但是,它适用于均为 C++ 的客户端和服务器。要求是服务器是运行ning 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() returns 错误的回复时。我最初的直觉是 python 端的编码错误。 QDataStream 是否需要特殊编码?

QDataStream::commitTransaction() 的文档:

bool QDataStream::commitTransaction()

Completes a read transaction. Returns true if no read errors have occurred during the transaction; otherwise returns false.

此外,在 运行ning 之后,这里是 c++ 客户端的输出:

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

当您想将 QDataStream 与运算符 >> 一起使用时,您必须遵循序列化格式。调用QDataStream.setVersion()select具体格式。

我只能找到 version 12 (applies from QDataStream::Qt_4_6 to QDataStream::Qt_4_9) and version 13 (QDataStream::Qt_5_0) 的文档。

版本 12 和 13 具有相同的 QString 序列化格式:

> If the string is null: 0xFFFFFFFF (quint32)

> Otherwise: The string length in bytes (quint32) followed by the data in 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 测试了代码。