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 :

delete et QTcpSocket


Sujet :

Qt

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Points : 219
    Points
    219
    Par défaut delete et QTcpSocket
    Bonjour,

    J'ai un petit problème avec le code ci-dessous:

    server.hpp :
    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
    #ifndef SERVER_HPP
    #define SERVER_HPP
     
     
     
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <QList>
     
     
     
    class Server : public QTcpServer
    {
     
      Q_OBJECT
     
    private slots:
      void addClient();
     
      void removeClient();
     
    private:
      QList<QTcpSocket *> clients;
     
    public:
      Server(quint16 port, QObject *parent=0);
     
    };
     
     
     
    #endif /* PACKET_HPP */
    server.cpp :
    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
    #include "server.hpp"
    #include <QThread>
    #include <iostream>
     
    using namespace std;
     
     
     
    Server::Server(quint16 port, QObject *parent)
      : QTcpServer(parent)
    {
     
      if(listen(QHostAddress::Any, port))
        {
          connect(this, SIGNAL(newConnection()), this, SLOT(addClient()));
        }
     
      return;
     
    }
     
     
    void Server::addClient()
    {
     
      cout << "addClient: current thread: " << QThread::currentThread() << endl;
      QTcpSocket *client=nextPendingConnection();
     
      if(client!=NULL)
        {
          cout << "New connection" << endl;
          cout << "New client thread: " << client->thread() << endl;
          connect(client, SIGNAL(disconnected()), this, SLOT(removeClient()));
          clients.append(client);
        }
     
      return;
     
    }
     
     
    void Server::removeClient()
    {
     
      cout << "removeClient: current thread: " << QThread::currentThread() << endl;
      QList<QTcpSocket *>::iterator it;
      QTcpSocket *client=static_cast<QTcpSocket *>(sender());
     
      for(it=clients.begin(); it!=clients.end(); ++it)
        {
          if(*it==client)
    	{
    	  cout << "Disconnection" << endl;
    	  cout << "Client thread: " << client->thread() << endl;
    	  clients.erase(it);
    	  delete *it;
    	  //(*it)->deleteLater();
    	  break;
    	}
        }
     
      return;
     
    }
    main.cpp :
    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
    #include "server.hpp"
    #include <QCoreApplication>
     
     
     
    #define SERVER_PORT 45200
     
     
     
    int main(int argc, char **argv)
    {
     
      QCoreApplication app(argc, argv);
      Server server(SERVER_PORT);
     
      return app.exec();
     
    }
    server.pro :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SOURCES+=main.cpp server.cpp
    HEADERS+=server.hpp
     
    TEMPLATE=app
     
    CONFIG=warn_on qt debug console
     
    QT=core network
    client.cpp :
    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
    #include <QTcpSocket>
    #include <iostream>
     
    using namespace std;
     
     
     
    int main(void)
    {
     
      QTcpSocket socket;
     
      socket.connectToHost("127.0.0.1", 45200);
      if(socket.waitForConnected(3000))
        {
          socket.disconnectFromHost();
        }
      else
        {
          cout << "Connection failed" << endl;
        }
     
      return 0;
     
    }
    client.pro :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SOURCES+=client.cpp
     
    TEMPLATE=app
     
    CONFIG=warn_on qt console debug
     
    QT=core network
    La compilation (sous Windows avec MinGW) se passe très bien deux exécutable sont créés (server.exe et client.exe). Dans un premier temps je lance le serveur puis je lance le client. Celui se connecte au serveur et ensuite se déconnecte. Cela à pour effet d'appeler le slot removeClient de la classe Server. Et c'est là que le problème survient: quand je fais un delete du QTcpSocket correspondant au client qui vient de se déconnecter j'ai un bon vieux segmentation fault. Si j'utilise deleteLater à la place du simple delete je n'ai plus de problème. J'aimerais comprendre pourquoi je ne peux pas faire directement un delete sur mon QTcpSocket. Dans la doc de Qt (dans la section Multithreaded Programming) il est dit, je cite :
    Calling delete on a QObject from another thread than the thread where it is created (or accessing the object in other ways) is unsafe unless you can guarantee that the object isn't processing events at the same moment.
    Or mon application n'est pas multithreadé et donc quand j'appelle delete sur le QTcpSocket l'objet ne peux être en train de traiter un évènement puisque je suis encore dans le slot removeClient et que par conséquent l'event loop n'a pas "la main". Voilà si quelqu'un peut m'expliquer en quoi mon raisonnement est incorrect je lui en serais reconnaissant.

    PS: il semble que ce problème ne se produise pas sur Linux (Ubuntu et centOS).

  2. #2
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Salut,

    Parce que tu le fais dans le slot auquel il est connecté. Or, lorsque toute fonction qui se termine, la main est rendu à la fonction appelante, à savoir l'une des méthodes de l'instance que tu viens de supprimer. *boum*

    Edit: si ça fonctionne par linux c'est par pur hasard. Une raison pourrait être que l'instance existe encore en mémoire parce que le gestionnaire de mémoire l'a laissé intact. Il ne faut pas t'y fier, c'est ce qui tombe dans la catégorie des comportements indéfinis.

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Points : 219
    Points
    219
    Par défaut
    Merci IrmatDen

    Oui le plantage parait logique et, une fois n'est pas coutume, je trouve que le comportement de Windows sur ce coup est meilleur que celui de Linux (je préfère voir mon application plantée que de la voir fonctionnée alors que mon code comporte un erreur).

  4. #4
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Citation Envoyé par Montag Voir le message
    Merci IrmatDen

    Oui le plantage parait logique et, une fois n'est pas coutume, je trouve que le comportement de Windows sur ce coup est meilleur que celui de Linux (je préfère voir mon application plantée que de la voir fonctionnée alors que mon code comporte un erreur).
    Ce serait pas parce que tu la compiles en mode debug par hasard?

  5. #5
    Membre actif
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Points : 219
    Points
    219
    Par défaut
    Le fait de compiler en mode debug ou en mode release ne change rien, ça plante sous Windows dès la première déconnexion alors que sous linux ça ne plante pas (ou peut-être que mon code plante sous Linux après un nombre indéterminé de connexion/déconnexion mais bon ça c'est le propre des comportements indéterminés).
    En tout cas merci de ton aide même si j'ai un peu honte de ne pas avoir trouver le problème tout seul

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

Discussions similaires

  1. Delete on cascade avec SQL server
    Par fadoua dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 14/01/2004, 11h02
  2. delete en cascade
    Par bruno270579 dans le forum Requêtes
    Réponses: 8
    Dernier message: 16/12/2003, 17h17
  3. fonction postgresql qui delete un enr
    Par access dans le forum Requêtes
    Réponses: 1
    Dernier message: 16/11/2003, 14h44
  4. [requête] DELETE + SELECT
    Par doohan dans le forum Requêtes
    Réponses: 6
    Dernier message: 07/07/2003, 12h27
  5. [langage] delete de fichier
    Par lolive dans le forum Langage
    Réponses: 2
    Dernier message: 24/04/2003, 15h04

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