[Android - Qt] communication par socket
Répondre à la discussion
Affichage des résultats 1 à 23 sur 23

[Android - Qt] communication par socket



  1. #1
    sandrecarpe

    [Android - Qt] communication par socket


    ------

    Bonjour, je fais une application cliente sous android qui communique avec son serveur sous Qt.
    Le client envoie un fichier que le serveur réceptionne et celui-ci envoie une chaine de caractère au client pour lui dire si tout s'est bien passé

    J'arrive sans problème à envoyer et réceptionner le fichier mais je n'arrive pas à envoyer le réponse du serveur, ça me paraît pourtant simple. Voici mon code

    Le client :
    Code:
    public boolean envoyer(File source)
    	{
    		Socket socket = null;
    		try
    		{
    			socket = new Socket(mIpServeur, PORT_FILE);
    
    			FileInputStream sourceFile = new FileInputStream(source);
    			DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
    			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    			
    			try
    			{
    				try
    				{					
    					long size = source.length();	// taille du fichier ; source est un objet File				
    					byte buffer[] = new byte[512 * 1024];
    
    					Log.e(getClass().getSimpleName() + ".envoyer(File source)", "envoi de " + source.getName() + " ; " + String.valueOf(size) + " bytes");
    
    					dout.writeLong(size);
    					dout.writeBytes(source.getName()+"\n");
    					
    					int nbLecture;
    					while ((nbLecture = sourceFile.read(buffer)) != -1)
    					{
    						dout.write(buffer, 0, nbLecture);						
    					}
    					sourceFile.close();
    					
    					
    					String reponse = reader.readLine();
    					Log.e("réponse", reponse);
    					
    				}
    				catch(SocketException e)
    				{
    					e.printStackTrace();
    				}
    				finally
    				{
    					dout.close();
    					socket.close();
    				}
    			}
    			finally
    			{	
    				sourceFile.close();
    			}
    		}
    		catch (IOException e)
    		{
    			e.printStackTrace();
    			return false;
    		}
    		finally
    		{
    			try {
    				if(socket != null) socket.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	 
    		return true; // Résultat OK  
    	}
    Et la partie serveur en C++/Qt :
    Code:
    void Torrent::reponse(int resultat)
    {
        qDebug() << "réponse" << resultat;
        QString data;
    
        if(resultat == 0)
            data = "downloadOk\n\r";
        else
            data = "Erreur : " + QString::number(resultat).toAscii() + "\n\r";
    
        mSocket->write(data.toStdString().c_str(), data.length()); //mSocket est un QTcpSocket
    }

    Actuellement le serveur est comme bloqué (la fonction reponse() n'est pas appelée), si je déconnecte le client le serveur se "débloque" et exécute sa tache comme prévue
    Pourriez-vous m'aider ?

    -----
    Dernière modification par sandrecarpe ; 26/07/2014 à 16h31.

  2. #2
    Jack
    Modérateur

    Re : [Android - Qt] communication par socket

    Le code coté client est trop succinct pour pouvoir interpréter le problème. Il faudrait voir comment est déclarée la socket, si le listen() est effectué correctement, etc.

    De plus, tu gères ta socket par événement?

  3. #3
    sandrecarpe

    Re : [Android - Qt] communication par socket

    Tout l'essentiel du côté client est là.. De quelle fonction listen() parlez-vous ?
    Que voulez-vous dire par gérer la socket par événement ?

  4. #4
    Jack
    Modérateur

    Re : [Android - Qt] communication par socket

    Erreur de ma part, je voulais parler du serveur

  5. A voir en vidéo sur Futura
  6. #5
    sandrecarpe

    Re : [Android - Qt] communication par socket

    Voilà plus de détails

    Code:
    void Serveur::demarrerServeur() // slot qui répond au signal clicked()
    {
        connect(mTcpServeurFichier, SIGNAL(newConnection()), this, SLOT(newClientFichier()));
        mTcpServeurFichier->listen(QHostAddress::Any, PORT_FICHIER);
    }
    
    void Serveur::newClientFichier()
    {
        mTcpSocketFichier = mTcpServeurFichier->nextPendingConnection();
        connect(mTcpSocketFichier, SIGNAL(readyRead()), this, SLOT(recevoirFichier()));
        connect(mTcpSocketFichier, SIGNAL(readChannelFinished()), this, SLOT(finReceptionFichier()));
    }
    
    void Serveur::finReceptionFichier()
    {
        qDebug() << "fin reception fichier";
        
        // C'est ici que la fameuse fonction reponse() est appelée
        reponse();
    
        mTailleFichier = 0;
        mNameFichier = "";
    }
    
    
    void Serveur::recevoirFichier()
    {
        QDataStream in(mTcpSocketFichier);
    
        //qDebug() << "byteAvailable" << mTcpSocketFichier->bytesAvailable();
        if(mTailleFichier == 0)
        {
            if(mTcpSocketFichier->bytesAvailable() < (int) sizeof(quint64))
                return;
    
            in >> mTailleFichier;
    
            qDebug() << " mTailleFichier " << mTailleFichier;
        }
    
    
        if(mNameFichier == "")
        {
            if(mTcpSocketFichier->bytesAvailable() < (int) sizeof(quint64) + sizeof(quint8))
                return;
    
            mNameFichier = QString(mTcpSocketFichier->readLine()).trimmed();
            qDebug() << "nameFichierRecu : " << mNameFichier;
    
            QString time = QDateTime::currentDateTime().toString();
            mTxtEditLog->append("<strong>" + time + "</strong> - " + mNameFichier);
        }
    
    
        QFile fichier(mNameFichier);
        if(!fichier.open(QIODevice::ReadWrite | QIODevice::Append))
        {
            qDebug() << "recevoirFichier() : impossible de créer le fichier";
            if(mNameFichier == "") mNameFichier = "inconnu";
        }
    
    
        char buf[512*1024] = {0};
    
        if(fichier.size() <= mTailleFichier)
        {
            if((mBytesRecu = mTcpSocketFichier->read(buf, 512*1024)) != -1)
                fichier.write(buf, mBytesRecu);
        }
    
        fichier.close();
    }

  7. #6
    Jack
    Modérateur

    Re : [Android - Qt] communication par socket

    ok.
    Tu n'as pas le code du constructeur? En principe on devrait y voir comment est créée la socket.
    Peux-tu vérifier également si les 2 slots sont bien appelés? Si ce n'est pas le cas, vérifie que les connect renvoient bien la bonne valeur (différente de 0 si je me souviens bien)

  8. #7
    sandrecarpe

    Re : [Android - Qt] communication par socket

    Voilà le constructeur

    Code:
    Serveur::Serveur()
    {
    
        mSocketUdp = new QUdpSocket;
        mTcpServeurFichier = new QTcpServer;
        mTcpSocketFichier = new QTcpSocket;
    
        mTailleFichier = 0;
        mNameFichier = "";
        mBytesRecu = 0;
    
        connect(mBtnDemarrerServeur, SIGNAL(clicked()), this, SLOT(demarrerServeur()));
        connect(mBtnArreterServeur, SIGNAL(clicked()), this, SLOT(arreterServeur()));
    
    }
    Le slot finReceptionFichier() est appelé seulement lorsque côté client je n'est pas le code qui est sensé lire la réponse du serveur

  9. #8
    Jack
    Modérateur

    Re : [Android - Qt] communication par socket

    Tu n'as pas fait les vérification que je t'avais demandées.

    Il faudrait également que tu vérifie le résultat de l'appel à listen.

    En fait il faut que tu testes tout pas à pas pour voir à partir de quand ça ne fonctionne pas normalement.

  10. #9
    sandrecarpe

    Re : [Android - Qt] communication par socket

    Salut, j'ai vérifié le retour des slots et l'appel du listen. J'ai également fermé mon QTcpSocket lors de l'appel de readChannelFinished(), voici le code :

    Code:
    void Serveur::demarrerServeur()
    {
        qDebug() << "demarrerServeur()";
    
    
        if(mSocketUdp->isOpen())
            mSocketUdp->close();
        if(mTcpServeurFichier->isListening())
            mTcpServeurFichier->close();
    
    
        mSocketUdp->bind(PORT_INFO);
        connect(mSocketUdp, SIGNAL(readyRead()), this, SLOT(connectionServeur()));
    
        connect(mTcpServeurFichier, SIGNAL(newConnection()), this, SLOT(newClientFichier()));
        if(mTcpServeurFichier->listen(QHostAddress::Any, PORT_FICHIER))
            qDebug() << "socket sur écoute";
    
    }
    //Jusque là tout se passe comme il faut
    
    
    void Serveur::newClientFichier()
    {
        mTcpSocketFichier = mTcpServeurFichier->nextPendingConnection();
        if(connect(mTcpSocketFichier, SIGNAL(readyRead()), this, SLOT(recevoirFichier())) &&
        connect(mTcpSocketFichier, SIGNAL(readChannelFinished()), this, SLOT(finReceptionFichier())))
        {
            qDebug() << "readyRead, readChannelFinished pret";
        }
    
    //aucun problème ici non plus
    }
    
    
    void Serveur::finReceptionFichier()
    {
    //PROBLEME ?
        QString data;
        if(resultat == 0)
            data = "downloadOk\r\n";
        else
            data = "Erreur : " + QString::number(resultat).toAscii() + "\r\n";
    
        mSocket->write(data.toStdString().c_str(), data.length());
    
    
    
        mTailleFichier = 0;
        mNameFichier = "";
        mTcpSocketFichier->close();
        qDebug() << "fin reception fichier";
    }
    
    
    void Serveur::recevoirFichier()
    {
        QDataStream in(mTcpSocketFichier);
    
        //qDebug() << "byteAvailable" << mTcpSocketFichier->bytesAvailable();
        if(mTailleFichier == 0)
        {
            if(mTcpSocketFichier->bytesAvailable() < (int) sizeof(quint64))
                return;
    
            in >> mTailleFichier;
    
            qDebug() << " mTailleFichier " << mTailleFichier;
        }
    
    
        if(mNameFichier == "")
        {
            if(mTcpSocketFichier->bytesAvailable() < (int) sizeof(quint64) + sizeof(quint8))
                return;
    
            mNameFichier = QString(mTcpSocketFichier->readLine()).trimmed();
            qDebug() << "nameFichierRecu : " << mNameFichier;
    
            QString time = QDateTime::currentDateTime().toString();
            mTxtEditLog->append("<strong>" + time + "</strong> - " + mNameFichier);
        }
    
    
        QFile fichier(mNameFichier);
        if(!fichier.open(QIODevice::ReadWrite | QIODevice::Append))
        {
            qDebug() << "recevoirFichier() : impossible de créer le fichier";
            if(mNameFichier == "") mNameFichier = "inconnu";
        }
    
    
        char buf[512*1024] = {0};
    
        if(fichier.size() <= mTailleFichier)
        {
            if((mBytesRecu = mTcpSocketFichier->read(buf, 512*1024)) != -1)
                fichier.write(buf, mBytesRecu);
        }
    
        fichier.close();
    //PROBLEME ???
    }
    Le signal readChannelFinished() régit uniquement lorsque, côté client je ne lis pas la réponse du serveur. Si je met le code pour lire la réponse côté client (android) le signal readChannelFinished n'est pas appelé
    Je ne sais donc pas de quel côté vient le soucis

  11. #10
    sandrecarpe

    Re : [Android - Qt] communication par socket

    Ah oui, et je reçois également un socketTimoutException côté client pendant que j'essai de lire la réponse

  12. #11
    satinas

    Re : [Android - Qt] communication par socket

    salut, à mon avis le signal readChannelFinished() qui déclenche la réponse du serveur, correspond à la fermeture de la session TCP, c'est à dire au disconnect. Hors ni le client ni le serveur ne ferme cette session, en fin de réception de fichier. Le client attend donc désespérément la réponse qui ne vient pas.
    Le serveur doit envoyer sa réponse en fin de réception ok du fichier, ou après un time-out si problème de réception, et c'est Android qui ferme la session (ou c'est le serveur si le client a disparu dans la nature entre-temps)

  13. #12
    sandrecarpe

    Re : [Android - Qt] communication par socket

    Très bonne piste, je vais voir ça, merci !

  14. #13
    sandrecarpe

    Re : [Android - Qt] communication par socket

    En effet c'était ça, merci beaucoup !

  15. #14
    sandrecarpe

    Re : [Android - Qt] communication par socket

    J'ai réussis a faire communiquer mes sockets presque correctement j'ai un problème avec les accents quand je lis la réponse du client côté serveur :

    Code:
    void Serveur::recevoirFichier()
    {
        QDataStream in(mTcpSocketFichier);
    
        //qDebug() << "byteAvailable" << mTcpSocketFichier->bytesAvailable();
        if(mTailleFichier == 0)
        {
            if(mTcpSocketFichier->bytesAvailable() < (int) sizeof(quint64))
                return;
    
            in >> mTailleFichier;
    
            qDebug() << " mTailleFichier " << mTailleFichier;
        }
    
    
        if(mNameFichier == "")
        {
            if(mTcpSocketFichier->bytesAvailable() < (int) sizeof(quint64) + sizeof(quint8))
                return;
    
            mNameFichier = QString(mTcpSocketFichier->readLine()).trimmed();
            qDebug() << "nameFichierRecu : " << mNameFichier;
    
            QString time = QDateTime::currentDateTime().toString();
            mTxtEditLog->append("<strong>" + time + "</strong> - " + mNameFichier);
        }
    
        if(mSavePath == "")
        {
            if(mTcpSocketFichier->bytesAvailable() < (int) sizeof(quint64) + sizeof(quint8) + sizeof(quint8))
                return;
    
            mSavePath = QString(mTcpSocketFichier->readLine()).trimmed();
            Arborescence::regexerDir(mSavePath);
            qDebug() << "mSavePath" << mSavePath; //PROBLEME ICI
        }
    
        QFile fichier(mNameFichier);
        if(!fichier.open(QIODevice::ReadWrite | QIODevice::Append))
        {
            qDebug() << "recevoirFichier() : impossible de créer le fichier";
            if(mNameFichier == "") mNameFichier = "inconnu";
        }
    
    
        char buf[512*1024] = {0};
    
        if(fichier.size() <= mTailleFichier)
        {
            if((mBytesRecu = mTcpSocketFichier->read(buf, 512*1024)) != -1)
                fichier.write(buf, mBytesRecu);
        }
        //qDebug() << "fichier.size()" << fichier.size();
        //qDebug() << "byteAvailable" << mTcpSocketFichier->bytesAvailable();
    
        if(mTcpSocketFichier->bytesAvailable() >= mTailleFichier)
        {
            qDebug() << "fin écriture fichier";
            action();
        }
    
        fichier.close();
    
    }

    Voici a quoi ressemble le contenu de mSavePath : C:/Users/anthony/Videos/Mes vid?os/peche
    L'accent est remplacé par un point d'interrogation :/



    Voici le code côté client :
    Code:
    socket = new Socket(mIpServeur, PORT_FILE);
    			socket.setSoTimeout(30000);
    			FileInputStream sourceFile = new FileInputStream(source);
    			DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
    			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    			
    			try
    			{					
    				long size = source.length();	// taille du fichier ; source est un objet File				
    				byte buffer[] = new byte[512 * 1024];
    
    				Log.e(getClass().getSimpleName() + ".envoyer(File source)", "envoi de " + source.getName() + " ; " + String.valueOf(size) + " bytes");
    
    				dout.writeLong(size);
    				dout.writeBytes(source.getName()+"\n");
    				dout.writeBytes(pathSave); // VARIABLE QUE J'ESSAI DE LIRE COTE SERVEUR
    Cette variable contient un chemin, je ne peux pas me passer des accents ou autres caractères spéciaux
    Avez-vous une solution à me proposer ?
    Dernière modification par sandrecarpe ; 28/07/2014 à 13h34.

  16. #15
    satinas

    Re : [Android - Qt] communication par socket

    mSavePath = QString::fromLatin1(mTcpSocket Fichier->readLine().trimmed());

    essaye aussi éventuellement les autres fonctions statiques QString::fromXyz

  17. #16
    sandrecarpe

    Re : [Android - Qt] communication par socket

    Ca a l'air de fonctionner, encore merci!

  18. #17
    sandrecarpe

    Re : [Android - Qt] communication par socket

    Désolé, j'ai un autre soucis, je pense que ça à le même rapport que le problème précédent avec les accents alors je poste ici.
    J'ai réussis à récupérer la variable qui contient : C:/Users/anthony/Videos/Mes vidéos

    Avec ce chemin je lance un logiciel en ligne de commande, mais il y a un problème avec l'espace. Le problème vient-il du logiciel ou faut-il que je fasse quelque chose de particulier sur la variable avant ? Comme l'"encoder" ?
    Dernière modification par sandrecarpe ; 28/07/2014 à 16h14.

  19. #18
    satinas

    Re : [Android - Qt] communication par socket

    Si la QString récupérée comporte bien l'espace et les accents, elle est bonne. Elle est stockée en UTF16 par Qt.
    Ensuite tu lances quoi et comment en ligne de commande, depuis Qt ou à la main ?
    S'il y a des espaces dans les arguments d'une ligne de commande, on utilise des guillemets, il y a ce post récent qui en parle.
    http://forums.futura-sciences.com/pr...h-espaces.html

  20. #19
    sandrecarpe

    Re : [Android - Qt] communication par socket

    La QString comporte bien l'espace et les accents. En fait le problème s'est les accents, pas les espaces
    Quand je lance mon logiciel en ligne de commande avec Windows je n'ai pas de problème, par contre je n'y arrive pas en C++
    Voici le code que j'utilise :
    Code:
        QString pathSaves = "C:/Users/anthony/Desktop/mé mé";
        QString commande = "/directory \"" + pathSaves + "\" " + fileNameTorrent;
        std::string commandLine = commande.toStdString();
        qDebug() << fileNameTorrent;
    
    
        WCHAR cmd[commandLine.length()];
        MultiByteToWideChar(0, 0, commandLine.c_str(), commandLine.length(), cmd, commandLine.length());
    
        SHELLEXECUTEINFO ExecuteInfo;
    
        memset(&ExecuteInfo, 0, sizeof(ExecuteInfo));
    
        ExecuteInfo.cbSize       = sizeof(ExecuteInfo);
        ExecuteInfo.fMask        = 0;
        ExecuteInfo.hwnd         = 0;
        ExecuteInfo.lpVerb       = L"open";// Operation to perform
        ExecuteInfo.lpFile       = L"chemin.exe";  // Application name
        ExecuteInfo.lpParameters = cmd;// Additional parameters
        ExecuteInfo.lpDirectory  = 0;
        ExecuteInfo.nShow        = SW_SHOW;
        ExecuteInfo.hInstApp     = 0;
    
        if(ShellExecuteEx(&ExecuteInfo))
            reponse(0);
        else
        {
            qDebug() << GetLastError();
            reponse(GetLastError());
        }
    Dernière modification par sandrecarpe ; 28/07/2014 à 18h18.

  21. #20
    satinas

    Re : [Android - Qt] communication par socket

    Depuis Qt5 l'encodage des chaînes est devenu plus ardu à maîtriser, sans doute car ils l'ont enrichi.

    Derrière ton
    QString pathSaves = "C:/Users/anthony/Desktop/mé mé";
    fais un qDebug() << pathSaves;
    Si les accents sont mal affichés, essaye
    QString pathSaves = QLatin1String("C:/Users/anthony/Desktop/mé mé");
    idem pour fileNameTorrent, il sort d'où ?

    Après, la conversion de tout ça en format d'exec Microsoft, là j'ai jamais fait, étant Qt pur et dur.
    Ce serait pas plus simple de lancer ton logiciel depuis Qt ?

  22. #21
    sandrecarpe

    Re : [Android - Qt] communication par socket

    qDebug() << pathSaves; m'affiche bien les accents
    fileNameTorrent est le chemin d'un fichier, il ne contient pas d'accent mais ça ne m'étonnerais pas que j'ai le même soucis si il en contenait

  23. #22
    satinas

    Re : [Android - Qt] communication par socket

    Pars d'un ShellExecuteEx() qui marche, avec des arguments sans espace ni accent, puis modifie un argument à la fois, pour isoler quel paramètre pose problème.
    C'est quoi la commande complète que tu tapes, lorsque il marche lancé à la main ?
    Dernière modification par satinas ; 28/07/2014 à 20h57.

  24. #23
    sandrecarpe

    Re : [Android - Qt] communication par socket

    J'ai utilisé qt pour lancer mon programme, c'est plus simple et ça marche !!!

Discussions similaires

  1. Connexion par socket entre smartphone Android et application Java sur PC
    Par chahbane dans le forum Programmation et langages, Algorithmique
    Réponses: 9
    Dernier message: 04/05/2014, 19h24
  2. communication via socket
    Par inviteb05fa7c2 dans le forum Internet - Réseau - Sécurité générale
    Réponses: 3
    Dernier message: 14/06/2012, 10h43
  3. Communication Socket
    Par inviteb28c79ed dans le forum Internet - Réseau - Sécurité générale
    Réponses: 3
    Dernier message: 15/05/2012, 08h47
  4. Socket 940
    Par invited65f1ec2 dans le forum Matériel - Hardware
    Réponses: 8
    Dernier message: 24/06/2009, 00h37
  5. qu'est ce qu'un socket?
    Par invite73653775 dans le forum Internet - Réseau - Sécurité générale
    Réponses: 4
    Dernier message: 03/04/2007, 17h31