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

C++ Discussion :

Pthreads et BSD sockets


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 17
    Points : 13
    Points
    13
    Par défaut Pthreads et BSD sockets
    Bonjour tout le monde, ca fait deux jours que je suis bloque la dessus, je commence un peu a désespérer peut être que ça vous sautera aux yeux sait on jamais??

    Voila j'écris un petit programme tout bête qui fait une addition de façon répartie (chaque client/serveur a un double, et il doit additionner le sien avec ceux de tous ses voisins (dont leur ip/port est donné dans un fichier texte.

    Mon problème est le suivant:
    lorsque mon client se connecte aux serveurs un par un de façon séquentielle il y arrive parfaitement et l'addition se fait comme il faut.
    Le problème est que cela est complètement inneficace et que je perds trop de temps dans les appels bloquants (ex. : un serveur ne répond pas...).

    La solution logique à ce problème est d'utiliser des threads (pthreads), de telle façon que mon client va contacter tour à tour chacun de ses voisins en utilisant un thread par connection.

    Mais le problème est justement la!!
    La connection se passe bien, mais au moment de l'appel de la fonction recv(), je recois la valeur 0, ce qui veut dire que le serveur a coupé la connection de l'autre coté, et pourtant je n'appelle pas la commande close...

    Voila si vous pouviez jeter un coup d'oeil ca m'aiderait vraiment beaucoup, les méthodes intéréssantes sont setServerSocket() et retrieveNextNode().

    Merci d'avance

    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
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
     
    #include "peer.h"
    using namespace std;
     
     
     
    peer* signalHandler;
     
    // Constructor for lru.
    peer::peer(char* fileName) {
      _fileName = fileName;
      _peerNumber = 0;
      _sum = 0;
      pthread_mutex_init(&_mutex, NULL);
     
      // Creates a new thread that will listens for incoming connections.
      pthread_create(&_serverThread, NULL, peer::setServer, (void*) this);
     
      // We set the global variable signal handler so that the static function
      // will know which object to use to handle the alarm signal.
      signalHandler = this;
      // Sets the alarm signal handler.
     
     
      // Parses the given input file.
      parseInputFile();
     
      _iterator = _neighborList.begin();
    }
     
     
    // Sets up the server socket
    void peer::setServerSocket() {
      // Sets up the socket.
      struct addrinfo hints;
      struct addrinfo *res;
     
      memset(&hints, 0, sizeof hints);
      hints.ai_family = AF_UNSPEC;
      hints.ai_socktype = SOCK_STREAM;
      hints.ai_flags = AI_PASSIVE; // Sets my ip adddress.
      getaddrinfo(NULL, "1030", &hints, &res);
     
      // Make a socket.
      int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     
      // Bind the socket to the right port.
      bind(sockfd, res->ai_addr, res->ai_addrlen);
     
      // Listen.
      listen(sockfd, 10);
     
      while(1) {
        struct sockaddr_storage their_addr;
        socklen_t addr_size = sizeof their_addr;
     
        int newSocket;
        newSocket = accept(sockfd, (struct sockaddr*) &their_addr, &addr_size);
     
        // MAYBE WE NEED TO CREATE ANOTHER THREAD HERE.
        char tosend[50];
        sprintf(tosend,"%g", _inputValue);
        // Send it.
     
        send(newSocket, tosend, strlen(tosend), 0);
     
        // Close the sending socket.
        // close(newSocket);
      }
    }
     
    // Adds its own sum, and then contacts all the other neighbors to 
    // add sequentially their data.
    void peer::computeSum() {
      _sum += _inputValue;
      _peerNumber++;
     
      while (_iterator != _neighborList.end()) {
        pthread_t thread;
        // Creates a new thread that will launch the function retrieveNextNode.
     
        pthread_create(&thread, NULL, peer::retrieve_func, (void*) this);
        // retrieveNextNode();
        // Next time we call retrieveNextNode, will be ready.
        _iterator++;
      }
    }
     
    // Connects to the next node and retrieves its data and try to add it, disconnects when done.
    void peer::retrieveNextNode() {
      string ipAddress = _iterator->getIp();
      string port = _iterator->getPort();
     
      // Sets up the socket.
      struct addrinfo hints;
      struct addrinfo *res;
     
      memset(&hints, 0, sizeof hints);
      hints.ai_family = AF_UNSPEC;
      hints.ai_socktype = SOCK_STREAM;
      getaddrinfo("localhost", "1030", &hints, &res);
      //  getaddrinfo(ipAddress.c_str(), port.c_str(), &hints, &res);
     
      // Make a socket.
      int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     
      // Connect.
      if (connect(sockfd, res->ai_addr, res->ai_addrlen)!= 0) {
        cerr << "Error on connection" << endl;  
        return;
      }
     
      // Read the value sent by the other host, and add it to the sum.
      char msgReceived[50];
      int len = strlen(msgReceived);
      recv(sockfd, msgReceived, len, 0);
     
      // Critical section, updates the sum and the number of peers.
      pthread_mutex_lock(&_mutex);
      _sum += atof(msgReceived);
      _peerNumber++;
      pthread_mutex_unlock(&_mutex);
     
      // Close the connection to this neighbor.
      close(sockfd);
    }
     
    void catch_alarm(int sig_num) {
      signalHandler->printOutput();
    }
     
    peer::~peer() {
     
    }
     
    // Parses the input file and puts all the data in data structures.
    void peer::parseInputFile() {
      _inputFile.open(_fileName);
      string inputValue = getNextLine();
      _inputValue = atof(inputValue.c_str());
     
      string threashold = getNextLine();
      _threashold = atoi(threashold.c_str());
      startTimer();
     
      // THERE IS A PROBLEM WITH PARSING HERE
      _port = getNextLine();
      // string::iterator it = _port.end() - 1;
      // _port.erase(it);
      //cout << strlen(_port.c_str());
     
      parseNeighborList();
    }
     
    // Starts the timer with the indicated threashold.
    void peer::startTimer() {
      alarm(_threashold);
    }
     
    void peer::parseNeighborList() {
      while (!_inputFile.eof()) {
        string neighbor = getNextLine();
        if (!neighbor.empty()) {
          size_t colonSeparator = neighbor.find(":");
     
          string ipAddress = neighbor.substr(0, colonSeparator);
     
          string port = neighbor.substr(colonSeparator+1, neighbor.length() - colonSeparator - 2);
          peerAddress toAdd(ipAddress, port);
          _neighborList.push_back(toAdd);
        }
      }
    }
     
    // Returns the next non empty line.
    string peer::getNextLine() {
      // We loop until we find a non empty line.
      string trimmed;
      do {
        _inputFile.getline(_buffer, 256);
        trimmed = trimLine(_buffer);
      } while(trimmed.length() == 1 && !_inputFile.eof()); 
      return trimmed;
    }
     
    string peer::trimLine(const char* toTrim) {
      string trimmed = string(toTrim);
      // Trims the white spaces.
      remove(trimmed.begin(), trimmed.end(), ' ');
      return trimmed;
    }
     
    void peer::printOutput() {
      printf("%f\t%d\n", _sum, _peerNumber);
    }
     
    void peer::printDebug() {
      cout << "Input value: " << _inputValue << endl;
      cout << "Time threashold: " << _threashold << endl;
      cout << "Port: " << _port << endl;
      cout << "Neighbors list: " << endl;
      list<peerAddress>::iterator it;
      for (it = _neighborList.begin(); it != _neighborList.end(); it++) {
        cout << "Ip: " << it->getIp() << ", port: " << it->getPort() << endl;
      }
    }
     
    int main(int argc, char **argv)
    {
      // The text file name is given as an input.
      if(argc != 2) {
        fprintf(stderr,"usage: peer <filename>\n");
        exit(1);
      }
      signal(SIGALRM, catch_alarm);
      peer myPeer(argv[1]);
      myPeer.printDebug();
      myPeer.computeSum();
      pthread_exit(NULL);
      return 0;
    }
    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
     
    #ifndef PEER_H
    #define PEER_H
     
    #include <list>
    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <cstring>
    #include <stdio.h>
    #include <stdlib.h>
    #include <algorithm>
    #include <csignal>
    #include <pthread.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <sys/wait.h>
    #include <netdb.h>
    #include <cassert>
    #include <signal.h>
    #include <netinet/in.h>
    #include "peerAddress.h"
     
    class peer {
     
      static void* retrieve_func(void* d) {
        ((peer*) d)->retrieveNextNode();
        return NULL;
      }
     
      static void* setServer(void* d) {
        ((peer*) d)->setServerSocket();    
        return NULL;
      }
     
     private:
      char* _fileName;
      char _buffer[256];
      std::ifstream _inputFile;
      double _inputValue;
      int _threashold;
      std::string _port;
      int _peerNumber;
      double _sum;
      pthread_mutex_t _mutex;
      std::list<peerAddress> _neighborList;
      std::list<peerAddress>::iterator _iterator;
     
      pthread_t _serverThread;
      // Server socket --> listener (will need to create other when incoming connections.
      int s;
     
     public:
      peer(char* fileName);
      ~peer();
      void parseInputFile();
      void parseNeighborList();
      std::string trimLine(const char* toTrim);
      std::string getNextLine();
      void printOutput();
      void startTimer();
      void printDebug();
      void computeSum();
      void retrieveNextNode();
      void setServerSocket();
    };
     
    #endif

    Merci encore!!

  2. #2
    Membre régulier Avatar de cynique
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 60
    Points : 72
    Points
    72
    Par défaut
    Citation Envoyé par cyberjoac Voir le message
    Mon problème est le suivant:
    lorsque mon client se connecte aux serveurs un par un de façon séquentielle il y arrive parfaitement et l'addition se fait comme il faut.
    Le problème est que cela est complètement inneficace et que je perds trop de temps dans les appels bloquants (ex. : un serveur ne répond pas...).

    La solution logique à ce problème est d'utiliser des threads (pthreads), de telle façon que mon client va contacter tour à tour chacun de ses voisins en utilisant un thread par connection.
    Mais non! Si tu as un problème de pertes de temps dans les appels bloquants, la solution est d'éviter les appels bloquants!

    Tu dois mettre tes sockets en mode non-bloquante, et puis tu peux utiliser select() pour savoir quel socket est prêt pour un appel vers "recv", "send" ou "accept".

    Fait attention! Touts ces appels peuvent échouer, et tu dois regarder errno pour savoir si c'est une vraie erreur ou juste un EWOULDBLOCK, qui signifie qu'il y a pas de données (recv), trop de données écrites (send) ou pas de nouveau socket (accept).

    Il y beaucoup de docs en ligne sur comment utilier select().

  3. #3
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Bonjour,
    Je dois avouer que ton code m'a un peu piquer les yeux (mélange assez barbare de C et C++)
    Ceci dit, je n'ai rien vu d'évident expliquant ton problème. As-tu essayé de regarder si il y a effectivement des échanges avec un sniffer réseau ?

Discussions similaires

  1. Problème socket & pthread
    Par Prayeriz dans le forum Développement
    Réponses: 4
    Dernier message: 26/03/2009, 17h07
  2. socket pthread connexion
    Par cmoibal dans le forum Réseau
    Réponses: 1
    Dernier message: 23/05/2007, 13h12
  3. Réponses: 8
    Dernier message: 18/04/2007, 14h26
  4. Sockets et pthreads
    Par Gruik dans le forum Réseau
    Réponses: 30
    Dernier message: 10/04/2007, 09h42

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