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

问题描述:

当前使用Qt的QTcpsocket库和python 3的套接字类。我已经获得了Qt的C++ fortune客户端/服务器示例来构建和正确运行。但是,它适用于C++的客户端和服务器。要求是服务器正在运行Python。Python 3套接字和QTcpsocket之间的通信失败(C++)

# 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()返回false。我最初的直觉是,python方面的编码是错误的。 QDataStream是否需要特殊编码?

的文档QDataStream :: commitTransaction():

布尔QDataStream :: commitTransaction()

完成读取事务。如果在交易过程中没有发生读取错误 ,则返回true;否则返回false

此外,运行程序后,这里是C的输出++客户端:

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

当你想使用QDataStream与运营商>>你必须遵循一个序列化格式。拨打QDataStream.setVersion()选择具体格式。

我已经能够找到的记录仅version 12(从应用到QDataStream::Qt_4_6QDataStream::Qt_4_9)和version 13QDataStream::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客户端的所有数据均采用big-endian顺序,因为它是QDataStream使用的隐式顺序。

我用Qt 5.9和序列号版本QDataStream::Qt_4_0测试了代码。

+0

谢谢是的,这使我能够在客户端正确接收消息。非常感谢你! – user3701175