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

  1. #1
    Futur Membre du Club
    Serveur en C client en C++ Qt TCP/IP Problème d'optimisation
    Bonjour,

    Je cherche depuis plusieurs jours une solution et je n'arrive pas. Sachant que je suis novice en réseau, je n'arrive pas non plus à trouvé des tuto ou des cours pour ce que je cherche.
    Mon Serveur client fonctionne sur la base de réception d'information. Mais j'aimerais chercher à gérer les problèmes liés à la déconnexion du client, su serveur etc afin d’éviter que l'un ou l'autre crache ou se termine.
    J'ai fais l’application avec un serveur en C++ sur Qt et un client en C et ça fonctionne très bien. Mais là je voulais faire l'inverse. C'est à dire un serveur en C et un client C++ sur Qt.

    Pourriez vous m'aider à comprendre ce qui ne va pas et ce qui manque sachant que j'ai fais plusieurs tentatives et ce que je vous présente est la dernière et peut être loin de la solution.

    Serveur en C :

    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
    #include <stdio.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #define MAX 120
    #define PORT 4242
    #define SA struct sockaddr
     
    // Function designed for chat between client and server.
    void func(int sockfd)
    {
        char buff[MAX];
        int n;
        float *h, *p, *t, *a;
        // infinite loop for chat
        for (;<img src="images/smilies/icon_wink.gif" border="0" alt="" title=";)" class="inlineimg" /> {
            bzero(buff, MAX);
     
            // read the message from client and copy it in buffer
            //read(sockfd, buff, sizeof(buff));
            // print buffer which contains the client contents
            printf("From client: %s\t To client : ", buff);
     
     
            bzero(buff, MAX);
            n = 0;
     
            // copy server message in the buffer
            sprintf(buff, "Informations...");
            sleep(1);
     
            // and send that buffer to client
            write(sockfd, buff, strlen(buff));
     
            read(sockfd, buff, sizeof(buff));
     
            // if msg contains "Exit" then server exit and chat ended.
            if (strncmp("exit", buff, 4) == 0) {
                printf("Server Exit...\n");
                //break;
                printf("avant close func");
            }
            bzero(buff, MAX);
     
        }
    }
     
    // Driver function
    int main()
    {
        int sockfd, connfd, len;
        struct sockaddr_in servaddr, cli;
        int a;
     
        while (1) {
     
     
            // socket create and verification
            sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (sockfd == -1) {
                printf("socket creation failed...\n");
                //exit(0);
            }
            else
                printf("Socket successfully created..\n");
            bzero(&servaddr, sizeof(servaddr));
     
            // assign IP, PORT
            servaddr.sin_family = AF_INET;
            servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
            servaddr.sin_port = htons(PORT);
     
     
            // Binding newly created socket to given IP and verification
            if ((a = bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
                printf("socket bind failed...\n");
                printf("erreur bind : %d",a);
                //exit(0);
            }
            else
                printf("Socket successfully binded..\n");
     
     
            // Now server is ready to listen and verification
            if ((listen(sockfd, 5)) != 0) {
                printf("Listen failed...\n");
                //exit(0);
            }
            else
                printf("Server listening..\n");
            len = sizeof(cli);
     
     
            // Accept the data packet from client and verification
            connfd = accept(sockfd, (SA*)&cli, &len);
            if (connfd < 0) {
                printf("server acccept failed...\n");
                //exit(0);
            }
            else
                printf("server acccept the client...\n");
     
            // Function for chatting between client and server
            func(connfd);
            printf("avant close");
        }
            printf("avant close");
            // After chatting close the socket
            close(sockfd);
            printf("après close");
     
        //return 0;
     
    }




    Client en C++ sur Qt avec un bouton "quitter" mais qui n'envoie que "exit" au serveur.

    Code Qt :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
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
     
    #include <QDebug>
    #include <QHostAddress>
     
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow),
        _socket(this)
    {
        ui->setupUi(this);
        _socket.connectToHost(QHostAddress("127.0.0.1"), 4242);
        connect(&_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
     
        connect(ui->actionQuitter, SIGNAL(triggered()), this, SLOT(endStream()));
    }
     
    MainWindow::~MainWindow()
    {
        delete ui;
    }
     
    void MainWindow::onReadyRead()
    {
        _socket.write(QByteArray("ok !\n"));
        QByteArray datas = _socket.readAll();
        qDebug() << datas;
        _socket.write(QByteArray("ok !\n"));
     
    }
     
    void MainWindow::endStream()
    {
        _socket.write(QByteArray("exit"));
     
        qDebug() << "ici";
        //close();
     
    }



    en démo, j'arrive à arrêter le serveur avec l'envoi du "exit" depuis le client mais il s'arrête malgré la boucle while après une tentative de reconnexion (le bind de la socket ne passe pas).
    Et si j'arrête le client complètement (fermer la fenêtre). Le serveur crache.

    Ce que je veux c'est de pouvoir laisser le serveur en écoute le temps que le client se reconnecte et de rester ouvert pour le cas où un autre client se connecte (mais ça en deuxième partie).


    Je vous remercie d'avance de votre aide.

  2. #2
    Rédacteur/Modérateur

    - Il n'y a quasi aucune vérification des retours de fonction
    - Le serveur ne peut accepter qu'un client puis (essaye de) recréer son socket sans fermer le précédent - ce qui va échouer
    - Pourquoi faire l'un en C et l'autre en C++ alors qu'avoir la même techno dans les 2 cas permettrait de factoriser du code ?

    Je t'invite à lire le cours dans la signature et en particulier https://bousk.developpez.com/cours/r...miers-pas/#LII & https://bousk.developpez.com/cours/r...-mini-serveur/ qui montrent à quoi un serveur simple devrait ressembler.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Futur Membre du Club
    Merci Bousk pour la réponse :

    - Je ne vois quelle retour serait nécessaire des fonctions

    - Comme je disais, j'ai tenté plusieurs possibilités et parmi elles, fermeture de la socket mais le serveur s'arrête quand même et ça boucle pas pour créer de nouveau la socket.

    - J'utilise du C car je travaille sur cible embarquée et pour apprendre à le faire en C

    Merci pour les tutos mais mon problème principale est de pouvoir faire cela en C.

  4. #4
    Rédacteur/Modérateur

    Le problème n'est pas le langage, si tu sais manipuler C et C++ tu peux très facilement passer de l'un à l'autre.
    Tu peux parfaitement arriver à un résultat similaire à https://bousk.developpez.com/cours/r...serveur/#LVI-C en C.
    read & write retournent aussi des codes d'erreur qu'il convient de vérifier... quand il y a une déconnexion en particulier. https://bousk.developpez.com/cours/r...-reception/#LI

    Combien de clients dois-tu gérer ?
    Quelle est la durée de vie d'un client ?

    Le plus simple reste d'utiliser le mode non bloquant imo. Mais si les clients sont peu nombreux et interagissent peu entre eux, un thread par client est envisageable.
    https://bousk.developpez.com/cours/r...-serveur/#LIII
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Futur Membre du Club
    Merci pour la réponse mais la solution était plus simple dans ce cas. Il manquait la fin du socket :



    _socket.disconnect();
    _socket.close();

    sinon le serveur essaye de se connecter sur un point de connexion encore occupé par la socket du client.
    Cela fonctionne bien en local 127.0.0.1

    Mais en passant le serveur sur la cible et tester sur les adresses de la box (déjà paramétrées et fonctionnent bien avec d'autres progs), le problème du bind revient.
    Je ne sais pas ce qui cloche avec ça.

  6. #6
    Futur Membre du Club
    J'ai retarder la boucle du serveur avec un sleep de 1 secondes et ça fonctionne maintenant.

    Je sais pas si c'est la la bonne solution ...

  7. #7
    Futur Membre du Club
    Citation Envoyé par benbel Voir le message
    J'ai retarder la boucle du serveur avec un sleep de 1 secondes et ça fonctionne maintenant.

    Je sais pas si c'est la la bonne solution ...
    Ce n'est pas la bonne solution ... imagine a chaque fois que tu te connectes a un serveur il y a un sleep ... tu mettrais 20ans a avoir ta vidéo youtube de 3min mdrr

    Je dirai que ton probleme vient du systeme ... tes sockets sont bloquante (Si tu ne sais pas ce que c'est : en gros quand tu executes une fonction dite bloquante (En l'occurence read et write sur une socket bloquante) ton systeme va mettre tout en pause pour executer la syscall ... or si ton client est deco ca fait des choses bizarre)

    Pour résoudre ton probleme je te conseille deja d'utiliser fcntl pour rendre ta socket non bloquante ... read te renverra 0 si ton client est deco.

    J'suis pas sur sur d'avoir bien compris ton probleme ... mais un serveur qui met pas ses socket en non bloquant est voué a l'echec je pense