2017-08-02 5 views
0

Utilisation de la bibliothèque QTcpsocket de Qt et de la classe socket de python 3 actuellement. J'ai déjà obtenu l'exemple client/serveur C++ de Qt pour construire et exécuter correctement. Cependant, c'est pour un client et un serveur qui sont tous les deux C++. L'exigence est que le serveur exécute Python.La communication échoue entre le socket Python 3 et 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) 

et

// 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 

et

// 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; 
     } 

} 

Ce qui finit par se produire est que le serveur reçoit le message du client sans problème, mais lorsque le serveur tente d'envoyer une réponse avec clientsocket.sendall(msg) , m_dataStream.commitTransaction() renvoie la valeur false. Mon instinct initial était que l'encodage était erroné du côté python. Est-ce que QDataStream nécessite un encodage spécial?

Documentation pour QDataStream :: commitTransaction():

bool QDataStream :: commitTransaction()

réalise une opération de lecture. Renvoie true si aucune erreur de lecture ne s'est produite pendant la transaction; sinon renvoie false.

En outre, après l'exécution, voici la sortie du C++ client:

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

Répondre

0

Lorsque vous souhaitez utiliser avec l'opérateur QDataStream>> vous devez suivre un format de sérialisation. L'appel QDataStream.setVersion() sélectionnez le format concret.

Je suis en mesure de documentation trouvée seulement pour version 12 (valable QDataStream::Qt_4_6-QDataStream::Qt_4_9) et version 13 (QDataStream::Qt_5_0).

version 12 et 13 ont le même format pour la sérialisation du QString:

> Si la chaîne est nulle: 0xFFFFFFFF (quint32)

> Sinon: La longueur de la chaîne en octets (quint32) suivi par les données en UTF-16

Lorsque vous appelez m_dataStream >> nextFortune, il s'attend à ce que les données entrantes soient dans le format décrit ci-dessus.

Le code en Python pour envoyer codé QString peut ressembler à ceci:

import struct 

msg = "Hello from the server".encode("utf-16be") 
clientsocket.sendall(struct.pack(">I", len(msg)) + msg) 
  • str.encode("utf-16be") - code pour la chaîne en UTF-16 avec l'ordre big-endian
  • struct.pack(">I", len(msg)) - crée un 32 bits l'entier non signé contient la longueur de la chaîne codée (I) dans l'ordre big-endian (>)

Toutes les données envoyées au client de Qt sont dans un ordre big-endian car c'est un ordre implicite que QDataStream utilise.

J'ai testé le code avec Qt 5.9 et la version de sérialisation QDataStream::Qt_4_0.

+0

Merci oui cela m'a permis de recevoir correctement le message sur le client. Merci beaucoup! – user3701175