IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Qt Discussion :

Convertion d'octets vers QString


Sujet :

Qt

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre actif
    Homme Profil pro
    http://tuatini-godard.me/
    Inscrit en
    Décembre 2010
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : http://tuatini-godard.me/

    Informations forums :
    Inscription : Décembre 2010
    Messages : 70
    Par défaut Convertion d'octets vers QString
    Bonjour à tous,
    Alors voilà aujourd'hui je fait face à un problème bien ennuyant .
    Je suis en train de réaliser une petite application client/serveur, la partie serveur est faite en Java
    et la partie cliente en C++ avec Qt
    Seulement voilà j'arrive très bien à échanger des informations de type int entre les deux entités (en utilisant
    le type qint32 sur la partie cliente) mais lorsqu'il s'agit d'échanger des chaînes de caractère... c'est
    une autre histoire.
    Alors voilà pour la partie serveur j'utilise un ByteBuffer dans lequel sera stocké toutes mes informations,
    puis poussés vers le client. Voici un bref aperçu:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    ByteBuffer buffer;
    DataOutputStream out = new DataOutputStream(socket.getOutputStream());
     
    c.setTime(tickets.get(i).getDate_depart());
    c2.setTime(tickets.get(i).getDate_arrivee());
    buffer.putInt(0);//Octects réservés pour la taille du block
    buffer.putInt(PacketsId.BILLET);//Identifiant du paquet
     
    buffer.putInt(tickets.get(i).getCode());
    buffer.putInt(tickets.get(i).getPrix());
     
    byte[] b2 = "Chaine de test".getBytes();
    System.out.println("chaine = " + new String(b2));
     
    buffer.put(b2);
    tempBuffer = new byte[buffer.position()];
     
    //Ecrase la réserve de 32bits au début du buffer (index 0) pour indiquer la taille
    //entière du buffer - la taille de deux int (8 octects) réservé pour indiquer 
    //la taille du message et l'id du paquet
    buffer.putInt(0, buffer.position() - 8);
    System.out.println("Taille buffer = " + buffer.position() + " (-8) ");
     
    for(int i = 0; i < buffer.position(); i++){
    	tempBuffer[i] = buffer.get(i);
    }
     
    out.write(tempBuffer);
    out.flush();
    buffer.clear();
    Jusque là tout est bien envoyé au client (normalement...). C'est lorsque je dois récupérer
    la chaine de caractère (en l'occurence b2) du coté client que j'ai quelques difficultés.
    J'ai essayé le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
     
    void NetworkUtil::dataReceived(MainWindow &parent, QTcpSocket *socket){
        QDataStream in(socket);
     
        //Test si le paquet concernant la taille du message est reçu
        if(receivingSize == 0){
            //Nous savons que le paquet concernant la taille fait 4 octects
            if(socket->bytesAvailable() < (int)sizeof(receivingSize))
                return;
            in >> receivingSize;
        }
     
        //Nous savons que le paquet concernant le packetId fait 4 octects.
        //Nous attendons donc l'arrivee de 4 octects consecutifs
        if(socket->bytesAvailable() < (int)sizeof(packetId))
            return;
     
        in >> packetId;
     
        qDebug() << "Packet Id = " << packetId;
     
        //Si le nombre d'octects disponibles dans le socket est inferieur à
        //la taille renseignee precedement dans receivingSize alors on
        //attends l'arrivee de plus de paquets
        if(socket->bytesAvailable() < receivingSize)
            return;
     
        //Ici nous possedons le message complet (socke dans la variable in)
        //ainsi que l'ID du paquet stocke dans packetId
     
        qDebug() << "Paquet: Taille du message (en octects) = " << receivingSize;
     
        switch(packetId){
        case PacketsId::NOMBRE_BILLETS_NON_RESERVES:
            in >> DataEnums::NB_PLACES_LIBRES;
            qDebug() << "Nb places = " << DataEnums::NB_PLACES_LIBRES;
            break;
        case PacketsId::BILLET:
            handleTicketPacket(in, receivingSize);
            break;
        }
     
        //Nous pouvons remettre receivingSize à 0
        receivingSize = 0;
     
        qDebug() << "Bits restants " << socket->bytesAvailable();
     
        if(socket->bytesAvailable() > 0)
            dataReceived(parent, socket);
     
    }
     
    void NetworkUtil::handleTicketPacket(QDataStream &in, qint32 receivingSize){
        Ticket tempTicket;
        Date tempDateDep, tempDateArr;
        qint32 tempInt32Buff;
        //32 est la taille occupé par les différents paramètres (int) du billet
        qint32 paysArraySize = receivingSize - 32;
        QChar tempStr[paysArraySize];
     
        in >> tempInt32Buff;
        tempTicket.setCode(tempInt32Buff);
        in >> tempInt32Buff;
        tempTicket.setPrix(tempInt32Buff);
     
         //Ici in pointe sur le début de la chaîne
         //J'ai enlevé de nombreuses lignes de
         //code inutiles
        for(int i = 0; i < paysArraySize; i++){
            in >> tempStr[i];
        }
     
        qDebug() << "tempStr = " << tempStr;
     
        tempTicket.setPaysArr(QString(tempStr));
    }
    mais sans succès... J'obtiens une chaine hexa du type 0x7fffc5021540.
    Je suis certain que mon dataStream "in" pointe bien sur la début de ma chaine
    lorsque je veux faire ma manipulation sur la chaine. De même QChar de Qt et String
    de Java sont bien encodés en UTF-8 non?
    Quelqu'un a une idée de comment je pourrais traiter la chaine reçu dans la partie client
    pour me voir restituer ma chaine d'origine envoyé depuis le programme Java?
    Merci d'avance.

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Par défaut
    Au vu de cette phrase de la doc:
    "The QChar class provides a 16-bit Unicode character"
    et encore plus de celle-là:
    "Most compilers treat it like a unsigned short"
    il parait fort probable qu'un QChar n'est pas du tout encodé en UTF8.

    QString::fromUtf8() serait peut-être plus approprié

  3. #3
    Membre actif
    Homme Profil pro
    http://tuatini-godard.me/
    Inscrit en
    Décembre 2010
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : http://tuatini-godard.me/

    Informations forums :
    Inscription : Décembre 2010
    Messages : 70
    Par défaut
    C'est cela en effet. Il me fallait écrire ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
        QChar tempStr[messageSize];
     
        for(int i = 0; i < messageSize; i++){
            in >> tempStr[i];
            //TODO Convert big endian to little endian (invert bytes)
     
        }
     
        return QString::fromUtf8((char *)tempStr);
    Cependant comme le commentaire l'indique, mes bits sont inversés à l'arrivée. Big endian obligé sur le réseau, c'est le protocole.
    Il me reste juste à trouver comment inverser les bits, ça ça ne devrait pas être bien compliqué .
    Merci pour ton geste

  4. #4
    Membre Expert
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Par défaut
    Il faudrait utiliser plutôt char au lieu de QChar pour tempStr, moyennant quoi il n'y a pas d'inversion de bits ou d'octets à faire. L'ordre des octets est inchangeable en UTF8, c'est uniquement en UTF16 ou 32 qu'il y a 2 ordres possibles.

  5. #5
    Membre actif
    Homme Profil pro
    http://tuatini-godard.me/
    Inscrit en
    Décembre 2010
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : http://tuatini-godard.me/

    Informations forums :
    Inscription : Décembre 2010
    Messages : 70
    Par défaut
    Merci pour ton aide mais j'ai fini par résoudre le problème des bits inversés. Le fait est que, en effet l'UTF-8 ne subit pas de conversions big/little endian mais c'est lors du transport des bits sur le réseau que ceux-ci sont inversés car les x86 utilisent le little endian mais tout transport d'informations à travers le réseau se fait en big endian et ce, indépendamment de la plateforme. Voici comment j'y suis parvenu:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
        qint32 messageSizeToUTF8 = messageSize / 2;
        QChar tempStr[messageSize];
     
        in.setByteOrder(QDataStream::LittleEndian);
        qDebug() << "messageSize = " << messageSize;
        for(int i = 0; i < messageSizeToUTF8; i++){
            in >> tempStr[i];
        }
     
        in.setByteOrder(QDataStream::BigEndian);
        return QString::fromUtf8(tempStr);
    Cependant, nouveau souci, comme vous devez le savoir l'UTF-8 adapte la taille (en octets) occupé par les caractères automatiquement selon si celui-ci fait partit de la table ASCII ou non. Donc si j'envoie une chaîne sur le réseau avec des "é" ou encore des "ç", je me retrouve avec un caractère qui pèse 3 octets... au lieu de 2... Donc au traitement des bits je me retrouve avec une chaîne plus courte qu'à l'envoie vu que je n'ai pas traité tous les octets dans ma boucle sans savoir si la chaîne possède ces caractères spéciaux... J'ai en effet essayé d'utiliser des char à la place de QChar mais les résultats n'étaient pas très convaincants...

  6. #6
    Membre Expert
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Par défaut
    Fais plutôt comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
        unsigned char tempStr[messageSize+1];
        qDebug() << "messageSize = " << messageSize;
        for(int i = 0; i < messageSize; i++){
            in >> tempStr[i];
            qDebug() << "octet=" << (int)tempStr[i];
        }
        tempStr[i]='\0';
        return QString::fromUtf8(tempStr);
    Car l'utilisation de QChar n'est pas la solution à ton problème, c'est au contraire la raison du problème. Lire les octets d'UTF8 par paires, c'est se tirer une balle dans le pied.

    Quand on transfère des données par le réseau par convention on les met en big-endian, mais ça concerne l'ordre des octets dans un mot de 16 ou 32 bits ou plus, ce n'est pas l'ordre des bits dans un octet et on n'applique pas ça à l'UTF8. De plus la couche réseau elle-même n'inverse rien, c'est de toute façon au programme client de le faire.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Tableau d'octets vers CString
    Par iMouss dans le forum MFC
    Réponses: 5
    Dernier message: 04/06/2008, 17h41
  2. Convertion d'entier vers une base et vice versa.
    Par Ptit_Dje dans le forum MS SQL Server
    Réponses: 0
    Dernier message: 04/09/2007, 10h14
  3. Convert de nvarchar vers Datetime, OVERFLOW
    Par Thargor dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 01/02/2007, 13h55
  4. Convertion Access 2 vers Acces 2000
    Par cathar_rhythm dans le forum Access
    Réponses: 3
    Dernier message: 26/09/2006, 09h50
  5. [C#] Convertion de structure vers Delphi .NET
    Par Laurent Dardenne dans le forum Windows Forms
    Réponses: 21
    Dernier message: 08/01/2005, 02h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo