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
测试了代码。
目前正在使用 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 returnsfalse
.
此外,在 运行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
测试了代码。