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

Multithreading Discussion :

Problème de gestion des threads après connexions multiples sur un serveur [QThread]


Sujet :

Multithreading

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut Problème de gestion des threads après connexions multiples sur un serveur
    Salut à tous! En ce moment je pars sur un projet de repartition de charge de plusieurs serveurs. J'essaie pour l'instant de simuler plusieurs connexions simultanées de clients sur un serveur en local grâce à des threads lancés en parallèle. Chaque thread se connecte sur le serveur, la dessus y'a aucun souci puisque le serveur reçoit bien le signal newConnection de chacun des threads. En revanche je n'arrive pas à ce que chaque thread transmette simultanément une info au serveur (signal ReadyRead) après avoir établit la connexion. Si par exemple, je lance 10 threads, il vont tous ce connecter sur le serveur mais un seul thread transmettra une information sur la socket. En telnet je n'ai pas ce souci la. Je vous laisse le codage.

    //serveur.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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    #include "serveur.h"
    #include "ui_serveur.h"
     
    serveur::serveur(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::serveur)
    {
        ui->setupUi(this);
        connect(ui->pushButtonEcouter, SIGNAL(clicked()),this, SLOT(ecouter()));
        connect(ui->pushButtonNePlusEcouter,SIGNAL(clicked()),this, SLOT(nePlusEcouter()));
        connect(ui->pushButtonRazCompteur,SIGNAL(clicked()),this,SLOT(razCompteur()));
        connect(ui->pushButtonInfosClients,SIGNAL(clicked()),this,SLOT(effacerZoneClients()));
        connect(ui->pushButtonMessagesClients,SIGNAL(clicked()),this,SLOT(effacerZoneMessages()));
        ui->lineEditPort->setText("20001");
        ui->pushButtonNePlusEcouter->setDisabled(true);
        ui->lineEditNbClients->setText("0");
     
    }
     
    serveur::~serveur()
    {
        delete ui;
    }
     
    void serveur::changeEvent(QEvent *e)
    {
        QMainWindow::changeEvent(e);
        switch (e->type()) {
        case QEvent::LanguageChange:
            ui->retranslateUi(this);
            break;
        default:
            break;
        }
    }
     
    void serveur::ecouter(){
     
        //on recupere le numero de port du serveur
        QString sPort = ui->lineEditPort->text();
        //conversion de ce port en un entier
        int port = sPort.toInt();
        //initialisation d'une socket de type serveur
            _socketServeurEcoute = new QTcpServer;
            _socketClient = new QTcpSocket;
                //on ecoute a present toutes adresses IP qui utilisent le port predefinit par le serveur
                if(_socketServeurEcoute->listen(QHostAddress::Any, port)==true){
                    qDebug()<<" je suis a l'ecoute";
     
                    //on ouvre la socket d'ecoute afin d'attendre qu'un client puisse se connecter sur le serveur
                    connect(_socketServeurEcoute, SIGNAL(newConnection()),this, SLOT(nouvelleConnexion()));
     
                    ui->pushButtonEcouter->setDisabled(true);
                    ui->pushButtonNePlusEcouter->setDisabled(false);
                }
                else    qDebug() << "probleme d'ecoute";
    }
     
    void serveur::nePlusEcouter(){
        qDebug() << "ne plus ecouter";
        ui->pushButtonNePlusEcouter->setDisabled(true);
        ui->pushButtonEcouter->setDisabled(false);
        _socketServeurEcoute->close();
        //on detruit la socket d'ecoute
        delete(_socketServeurEcoute);
        this->razCompteur();
        this->effacerZoneClients();
        this->effacerZoneMessages();
    }
     
    void serveur::nouvelleConnexion(){
     
        //le serveur ajoute un nouveau client
        _socketClient = _socketServeurEcoute->nextPendingConnection();
        //on recupere l'adresse IP de ce nouveau client
        QHostAddress peer = _socketClient->peerAddress();
     
        //on recupere le nombre de clients avant cette nouvelle connexion
        QString sNbClientsAvant = ui->lineEditNbClients->text();
        //conversion de ce port en un entier
        int nbClientsActuel;
     
        QString sNbClientsActuel;
        nbClientsActuel = sNbClientsAvant.toInt() + 1;
        sNbClientsActuel.setNum(nbClientsActuel);
        ui->lineEditNbClients->setText(sNbClientsActuel);
        ui->plainTextEditInfos->appendPlainText("IP : "+ peer.toString() + " | numero : " + sNbClientsActuel);
        //ce slot va detecter que des donnees ont ete transmises de la part du client
        connect(_socketClient,SIGNAL(readyRead()),this, SLOT(recevoir()));
     
    }
     
    void serveur::razCompteur(){
        ui->lineEditNbClients->setText("0");
    }
     
    void serveur::effacerZoneClients(){
        ui->plainTextEditInfos->setPlainText("");
    }
     
    void serveur::effacerZoneMessages(){
        ui->plainTextEditMessagesClients->setPlainText("");
    }
     
    void serveur::recevoir(){
        qDebug()<< " signal readyRead Recu";
        //lecture de la socket du client
        QByteArray reponse = _socketClient->readAll();
        QString sRep(reponse);
     
        if (sRep == ""){
            ui->plainTextEditMessagesClients->appendPlainText("Erreur de reception");
        }
     
        else {
            ui->plainTextEditMessagesClients->appendPlainText(sRep);
        }
     
        QString message = "reponse du serveur : ";
        message += sRep;
        QTextStream socketStream(_socketClient);
     
        socketStream << message << endl;
    }
    //serveur.h
    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
     
    #ifndef SERVEUR_H
    #define SERVEUR_H
     
    #include <QMainWindow>
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <QHostAddress>
    #include <QDebug>
    #include <QByteArray>
    #include "QThread"
    #include "threadServeur.h"
     
    namespace Ui {
        class serveur;
    }
     
    class serveur : public QMainWindow{
        Q_OBJECT
    public:
        serveur(QWidget *parent = 0);
        ~serveur();
     
    protected:
        void changeEvent(QEvent *e);
     
    private:
     
        Ui::serveur *ui;
        QTcpServer *_socketServeurEcoute;
        QTcpSocket *_socketClient;
        ThreadServeur * _threadServeur;
     
    private slots:
        void ecouter();
        void nePlusEcouter();
        void nouvelleConnexion();
        void recevoir();
        void effacerZoneClients();
        void razCompteur();
        void effacerZoneMessages();
    };
     
    #endif // SERVEUR_H
    //clients.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
    #include "clients.h"
    #include "ui_clients.h"
     
    clients::clients(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::clients)
    {
        ui->setupUi(this);
        ui->lineEditHost->setText("127.0.0.1");
        ui->lineEditPort->setText("20001");
        connect(ui->pushButtonAjoutClients,SIGNAL(clicked()),this, SLOT(ajoutClients()));
     
     
    }
     
    clients::~clients()
    {
        delete ui;
    }
     
    void clients::changeEvent(QEvent *e)
    {
        QMainWindow::changeEvent(e);
        switch (e->type()) {
        case QEvent::LanguageChange:
            ui->retranslateUi(this);
            break;
        default:
            break;
        }
    }
    void clients::ajoutClients(){
     
        //recuperation de l'adresse IP dans l'IHM
        host= ui->lineEditHost->text();
        //recuperation du numero de port dans l'IHM
        port= (ui->lineEditPort->text()).toInt();
        //on se connecte a cette adresse IP ainsi que son numero de port grace a la socket
        for(int i=0;i<10;i++){
        _threadClients = new ThreadClients(host,port);
        _threadClients->run();
        usleep(10000);
        }
    }
    //clients.h
    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
     
    #ifndef CLIENTS_H
    #define CLIENTS_H
     
    #include <QMainWindow>
    #include <QHostAddress>
    #include <QDebug>
    #include <QTextStream>
    #include "threadClients.h"
     
    namespace Ui {
        class clients;
    }
     
    class clients : public QMainWindow{
        Q_OBJECT
    public:
        clients(QWidget *parent = 0);
        ~clients();
    protected:
        void changeEvent(QEvent *e);
     
    private:
        Ui::clients *ui;
        ThreadClients *_threadClients;
        QString host;
        int port;
     
    private slots:
     
        void ajoutClients();
     
    };
     
     
    #endif // CLIENTS_H
    //threadClients.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
    #include "threadClients.h"
     
    ThreadClients::ThreadClients(QString host,int port){
        _host = host;
        _port = port;
     
    }
     
    ThreadClients::~ThreadClients(){
    }
     
    void ThreadClients::run()
    {
     
        _socket = new QTcpSocket;
        _socket->connectToHost(_host,_port);
     
        if(_socket->waitForConnected(1000))
        {
            QTextStream socketStream(_socket);
            QString message = "messageClient";
            qDebug() << message;
            socketStream << message << endl;
        }
     
        else
        {
            qDebug() << "hs";
        }
     
     
    }

    //threadClients.h
    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
    #ifndef THREADCLIENTS_H
    #define THREADCLIENTS_H
    #include <QThread>
    #include <QDebug>
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <QTextStream>
     
    class ThreadClients : public QThread
    {
     
    private:
        QString _host;
        int _port;
     
     
    public:
        ThreadClients(QString,int);
        ~ThreadClients();
        void run();
        QTcpSocket * _socket;
     
     
    };
    #endif // THREADCLIENTS_H

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut
    Si par exemple, je lance 10 threads, il vont tous ce connecter sur le serveur mais un seul thread transmettra une information sur la socket.
    Comment sais tu qu'un seul envoie l'information ? Je n'ai pas lu ton code en détail, mais si tu bases cette information sur le fait que ton serveur ne reçoit qu'un seul paquet, alors je t'invite à te renseigner sur l'algorithme de Nagle.

    En gros, des couches basses de ton système vont concaténer tes paquets TCP afin d'améliorer leur rendement données utiles / entête .

    Un "flush()" règlera sans doute ton problème (si cela en est bien la cause).

    Sinon, donne nous plus d'informations sur ce qui est reçu et sur ce qui se passe "mal".

    G.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut
    En fait la méthode run est bien parcouru pour chaque thread puisque le serveur reçoit le signal ReadyRead autant de fois qu'il y a de threads sauf que le problème c'est qu'il reçoit tout en une seule fois même si je mets un intervalle de quelques secondes entre les threads.
    Je vais toujours tester un flush et je te donnerai plus d'info quant au résultat.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut
    Un flush ne change pas la donne, mais un screenshot vaut peut être mieux que des explications.

  5. #5
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Salut.
    Comme là dit gulish, si tu veux que les données parte tous de suite, il faut faire un flush.
    Sur de grosse donnée, il te faudra l'appeler plusieurs fois et vérifier le nombre d'octet qu'il reste à envoyer
    http://qt.developpez.com/doc/latest/...l#bytestowrite

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 23
    Par défaut
    Oui vous avez raison j'avais mis mon flush du coté serveur, une erreur de débutant . Finalement sa fonctionne sur les 10 clients qui se connectent, 8 arrivent à transmettrent la trame quasimultanément. Merci encore !

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 24/04/2008, 15h23
  2. Réponses: 4
    Dernier message: 03/02/2006, 11h06
  3. [VB6 + Mysql]Gestion des erreurs de connexion
    Par Deejoh dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 25/01/2006, 20h01
  4. GEstion des thread
    Par Julien Dufour dans le forum Access
    Réponses: 8
    Dernier message: 06/10/2004, 14h28
  5. [reseaux] Gestion des threads en perl
    Par totox17 dans le forum Programmation et administration système
    Réponses: 2
    Dernier message: 28/11/2002, 09h40

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