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

Développement Discussion :

[select]serveur TCP : probleme suite a un accept!


Sujet :

Développement

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 17
    Points : 9
    Points
    9
    Par défaut [select]serveur TCP : probleme suite a un accept!
    Bonjour a tous,

    Je developpe un systeme de client/serveur en C, et j'ai décidé de ne pas utiliser de threads, mais de me mettre (enfin) au select!

    Donc j'ai une socket qui ecoute les connexion entrantes, et qui crée une nouvelle socket pour chaque client qui arrive. Toutes ces sockets sont dans deux fd_set pour pouvoir etre surveillée (y compris la socket qui ecoute les connexions).

    Voila donc le bout de code correspondant :

    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
    
    	while(1)
    	{
    
    		FD_ZERO(&readfs);
    		FD_ZERO(&writefs);
    
    		FD_SET(listenfd,&readfs);
    
    		for(int i=0;i<nbClient;i++)
    		{
    			FD_SET(connfd[i],&readfs);
    			FD_SET(connfd[i],&writefs);
    
    		}
    
    		tv.tv_sec = 1;
    		tv.tv_usec = 500000;
    
    		int retval = select(maxdescriptor + 1, &readfs, &writefs, NULL, &tv);
    
    		if (retval==0)
    		{
    			printf("Rien sur la ligne.... nbclient : %d\n",nbClient);
    
    		}
    		else
    		{
    
    			if (FD_ISSET (listenfd, &readfs))
    			{
    				printf("Nouvelle connexion!\n");
    				connfd[nbClient] = accept(listenfd, (struct sockaddr *) &clientInfos, &client_len);
    				if(connfd[nbClient]>maxdescriptor)
    					maxdescriptor=connfd[nbClient];
    
    
    				nbClient++;
    
    			}
    
    			for(int i=0;i<nbClient;i++)
    			{
    
    				if (FD_ISSET (connfd[i], &readfs))
    				{
    					recvfrom(connfd[i], data, data_len, 0, (struct sockaddr *)&clientInfos, &client_len);
    					printf("cas : recv\n");
    				}
    
    				if (FD_ISSET (connfd[i], &writefs))
    				{
    					char data[3]="OK";
    					
    					sendto(connfd[i],data,3,0,(struct sockaddr *)&clientInfos,client_len);
    					printf("cas : write\n");
    				}
    
    			}
    
    
    		}
    	
    
    	}
    Donc voila ce qui se passe :

    Je lance le serveur, et il affiche qu'il n'y a rien sur la ligne toutes les 1.5 secondes.
    Puis je lance le client, a ce moment la, la connexion est acceptée, puis le serveur affiche, en boucle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    cas : recv
    cas : write
    cas : recv
    cas : write
    cas : recv
    cas : write
    etc...
    Et je ne comprend pas puisque je n'envoie rien ni n'ecrit rien sur la socket connfd[0]... Ai-je oublié quelque chose? N'ai-je pas tout a fait compris comment utiliser le select? (c'est bien possible vu que c'est la premiere fois que je l'utilise..)

    Voila si quelqu'un pouvait m'eclairer je lui en serait tres reconnaissant je m'arrache les cheveux sur ce select !

  2. #2
    Membre expérimenté
    Avatar de granquet
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    1 201
    Détails du profil
    Informations personnelles :
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 201
    Points : 1 421
    Points
    1 421
    Par défaut
    t'es sur de faire du TCP?
    avec des sendto et recvfrom?

    en dehors de ça, le reste du code semble correct.

    peut-on voir le code du client?
    click my www
    ............|___
    ...................\
    .................._|_
    ..................\ /
    ..................."

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 17
    Points : 9
    Points
    9
    Par défaut
    Ah mais oui je suis une nouille .. Mon client se connectait, et se fermait ensuite, donc cela engendrait surement des erreurs ..

    J'ai aussi corrigé mes rcvfrom et sendto en recv et send ! Merci a toi!

    Sinon j'ai une question en rapport avec les sockets en ecriture : avec mon code tel qu'il est, le select trouve toujours que ma socket est prete en ecriture, j'en déduis que peut etre une socket est toujours prete en ecriture !

    Donc est ce que la meilleure chose a faire, est d'ajouter ma socket au fd_set writefs uniquement lorsque j'ai quelque chose a envoyer?

    En tenant a jour un tableau des messages a envoyer, et lorsque je veux que quelque chose parte dans la socket, je met mon message dans ce tableau a l'index qui correspont a la socket, j'ajoute la socket au fd_set, et j'attend le prochain tour de boucle?

    Et derniere chose : lorsque un client se connecte, le serveur fait :

    connfd[nbClient] = accept(listenfd, (struct sockaddr *) &clientInfos, &client_len);

    Est ce important pour la suite de stocker clientInfos et d'en avoir un par client, ou non ?

  4. #4
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Je te conseille quand tu commences, de bien développer séparement le client du serveur. En utilisant d'autres programmes, comme par exemple la commande "socket" sous Unix qui te permet de te connecter en TCP à ton serveur. Ca te permet de faire une connexion et d'envoyer des paquets, ça peut être très utile pour le démarrage, surtout quand tu n'es pas sûr de la base de ton serveur.

    Est ce important pour la suite de stocker clientInfos et d'en avoir un par client, ou non ?
    Ca dépend de si tu as besoin de l'adresse IP ou du port du client par la suite.
    Je ne répondrai à aucune question technique en privé

  5. #5
    Membre expérimenté
    Avatar de granquet
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    1 201
    Détails du profil
    Informations personnelles :
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 201
    Points : 1 421
    Points
    1 421
    Par défaut
    Citation Envoyé par phraides
    Ah mais oui je suis une nouille .. Mon client se connectait, et se fermait ensuite, donc cela engendrait surement des erreurs ..
    ça engendre que tu as une déconnexion.
    une déconnexion d'un client se traduit coté serveur par quelque chose a lire sur ta socket. (recv renvoit 0)

    de manière générale, il faut TOUJOURS tester le retour des fonctions (fin, celles qui renvoient des choses intéressantes, recv et send font parti des fonctions renvoyant des choses intéressantes )

    Sinon j'ai une question en rapport avec les sockets en ecriture : avec mon code tel qu'il est, le select trouve toujours que ma socket est prete en ecriture, j'en déduis que peut etre une socket est toujours prete en ecriture !

    Donc est ce que la meilleure chose a faire, est d'ajouter ma socket au fd_set writefs uniquement lorsque j'ai quelque chose a envoyer?
    un socket peux ne pas être prêt a send (congestion du reseau par exemple).
    en règle générale dans des petites applications non critique, je le considère comme étant toujours prêt a send.
    sinon je fait une machine a états finis qui reprend plus ou moins les états de TCP (en attente de data, prêt a envoyer, déconnecté...): c'est assez lourd a mettre en place, mais ça paye
    click my www
    ............|___
    ...................\
    .................._|_
    ..................\ /
    ..................."

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 17
    Points : 9
    Points
    9
    Par défaut
    Merci pour vos réponses !

    Mon client/serveur marche bien maintenant, j'ai fait comme tu a dis une sorte de machine a etat dependant de la "phase" ou se trouve le client et le serveur, j'ai géré la deconnexion des clients, etc ...

    Il y a quelques trucs que je ne comprend pas, mais que j'ai reussit a ne pas utiliser, par exemple lorsque je met STDIN (fd 0) dans le select, celui ci detecte toujours une activité sur mon socket qui listen les nouvelles connexions .. Ca n'a aucun sens !!
    (Je code sous windows, peut etre que le stdin ne fonctionne pas de la meme facon que sous unix je ne sais pas !)

    Ou encore le buffer où je fait mes recv(), et celui où je fais mes send() doivent etre les memes sinon le programme me fait une erreur fatale .. Je ne comprend toujours pas !

    Enfin comme je l'ai dit je me debrouille avec un seul buffer pour tout faire, et pour l'instant cela marche bien. Pour l'entrée clavier j'utilise _kbhit(), et _getch() et non un select sur stdin !

    Est ce que le fait d'utiliser ce fameux select, plutot que de creer un thread par nouveau client, rend mon serveur plus leger ? En fait c'est dans le but de faire du temps reel, c'est pour cela que j'ai opté pour cette méthode!

  7. #7
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    J'avais donné ce code d'exemple (mais pour Unix) :


    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
    while(1)
      {
        maxfd = fdConnection+1;
        if(maxfd< STDIN_FILENO+1)
          maxfd = STDIN_FILENO+1;
    
        FD_ZERO(&setfd);
        FD_SET(fdConnection, &setfd);
        FD_SET(STDIN_FILENO, &setfd);
    
        /** repositionnement pour chaque client */
    
        clientListBegin();
        for(i = 0; i<clientListGetSize(); i++)
        {
          int lsocket = clientListGetSocket(i);
          FD_SET(lsocket, &setfd);
          if(lsocket+1>maxfd)
            maxfd = lsocket+1;
        }
        clientListEnd();
    
        if(select(maxfd, &setfd, 0,0,0) == -1)
        {
          perror("select");
          exit(EXIT_FAILURE);
        }
    
        if(FD_ISSET(STDIN_FILENO, &setfd))
        {
          fprintf(stderr, "Close program : \n");
          break;
        }
        /*on matte ce que les gens racontent*/
        clientListBegin();
        for(i = 0; i<clientListGetSize(); i++)
        {
          lsocket = clientListGetSocket(i);
          if(FD_ISSET(lsocket, &setfd))
          {
            //tailleget = read(lsocket, buffer, sizeof(buffer)-1);
            tailleget =  recv(lsocket, buffer, sizeof(buffer)-1, MSG_PEEK);
            if(tailleget == -1)
            {
              perror("recv");
              continue;
            }
    
            if(tailleget == 0)
            {
              fprintf(stderr, "Disconnection\n");
              close(lsocket);
              clientListPrepareToRemove(i);
              continue;
            }
    
            char *  realEnd;
    
            realEnd = memchr(buffer, '\n', tailleget);
            if(realEnd == NULL)
            {
              fprintf(stderr, "Server receive a too long packet\n");
              continue;
            }
    
            tailleget = realEnd - buffer + 1;
    
            tailleget = recv(lsocket, buffer, tailleget,0 );
    
    
            if(tailleget == -1)
            { /*n'arrivera jamais ici*/
              perror("recv");
            }
            else
            {
              /*fin de connexion ?*/  /*n'arrivera jamais ici*/
              if(tailleget == 0)
              {
                fprintf(stderr, "Disconnection...\n");
                close(lsocket);
                clientListPrepareToRemove(i);
              }
              else
              {
                buffer[tailleget] = '\0';
                printf(" * PACKET :  : %s\n", buffer);
                serverInterpreter(buffer, lsocket);
                DEBUG("End serverInterpreter");
              }
            }
          }
        }
        clientListEnd();
    
        DEBUG("debut demande de connexion");
    
    
        /* nouvelle demande de connexion ?*/
        if(FD_ISSET(fdConnection, &setfd))
        {
          fprintf(stderr, "Demande de connexion....\n");
          tailleaddr = sizeof addrClient;
          clientSocket = accept(fdConnection, (struct sockaddr*) &addrClient,
                                &tailleaddr);
          if(clientSocket == -1)
          {
            perror("accept");
            continue;
          }
          //fprintf(stderr, " * Port : %d", ntohs(addrClient.sin_port));
    
          if(clientListAdd(clientSocket, addrClient.sin_addr.s_addr, addrClient.sin_port) == -1)
          {
            fprintf(stderr, "Ajout client impossible\n");
          }
        }
    
        DEBUG("fin demande de connexion");
    
      }
    Est ce que le fait d'utiliser ce fameux select, plutot que de creer un thread par nouveau client, rend mon serveur plus leger ? En fait c'est dans le but de faire du temps reel, c'est pour cela que j'ai opté pour cette méthode!
    L'utilisation de thread est toujours quelque chose d'extrement compliqué, d'autant plus en C je trouve. Je pense qu'il faut les utiliser que si on en a vraiment besoin, c'est à dire : pour des tâches lourdes, typiquement le transfert d'un fichier, le chargement en mémoire de quelque chose de très gros (par exemple un fichier). Sinon, ça peut très bien se faire avec des select, ça rend le programme en général moins complexe à développer.

    Ou encore le buffer où je fait mes recv(), et celui où je fais mes send() doivent etre les memes sinon le programme me fait une erreur fatale .. Je ne comprend toujours pas !
    Tu ne testes jamais les valeurs de retour cela dit, c'est extrement grave et cela peut amener à des plantages systématiques.

    De plus, utilises fprintf(stderr, "") au lieu de printf, ça te permettra de vraiment voir le dernier message d'erreur.
    A mon avis, l'erreur que tu as, c'est soit un Relais brisé, soit une Erreur de segmentation.

    Un relais brisé (broken pipe) est très fréquent si tu essayes d'écrire dans un socket TCP que la personne en face a fermé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    			FD_SET(connfd[i],&readfs);
    			FD_SET(connfd[i],&writefs);
    Je ne comprend pas l'utilité d'avoir deux fd_set... Il n'y a qu'un canal de communication entre deux personnes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (FD_ISSET (listenfd, &readfs))
    			{
    				printf("Nouvelle connexion!\n");
    Je ne comprend pas du tout ce que tu fais, tu fais : FD_SET(connfd[i],&readfs) mais ce fd_set sert pour les demandes de connexion ???? Il ne faut qu'un unique socket pour les tentative de connexion
    Je ne répondrai à aucune question technique en privé

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 17
    Points : 9
    Points
    9
    Par défaut
    Alors pour te repondre millie,

    Voici mon code mis a jour, corrigé, et commenté :

    C'est la boucle principale :

    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
    while(1)
    	{
    		FD_ZERO(&readfs); // Read fd_set set to 0
    		FD_SET(listenfd,&readfs); // Listening socket set in read fd_set
    	
    		// For each alive client, we monitor its socket
    		for(int i=0;i<clientMax;i++)
    		{
    			if(clientAlive[i]==0)
    				continue;
    			FD_SET(connfd[i],&readfs);
    		}
    
    		// Timeout reinitialisation
    		tv.tv_sec = 0;
    		tv.tv_usec = 500000;
    
    		// If keyboard activity
    		if(_kbhit())
    		{
    			char c=_getch(); // We retrieve the key
    
    			// Phase 0 : hitting i starts phase 1
    			if(phase==0 && c=='i')
    			{
    				phase = 1; // Next phase
    	
    				// For each alive client, we send an init cam request
    				for(int i=0;i<clientMax;i++)
    				{
    					if(clientAlive[i]==0)
    						continue;
    
    					printf("client %d : init cam request sent\n",i);
    
    					// According to the defined protocol, data in phase 0 must begin with 0x01
    					data[0]=0x01;
    					data[1]=0x00;
    					
    					// We add the client socket in write fd_set, to send him the data
    					FD_SET(connfd[i],&writefs);
    				}
    			}
    
    			/***** Je vous passe les autres phases *****/
    
    				// We reset captureNeeded boolean
    				captureNeeded=0;
    
    			}
    
    		// We monitor the activity of the sockets set in the Read and Write fd_set
    		int retval = select(maxdescriptor + 1, &readfs, &writefs, NULL , &tv);
    
    		// If 0 : no activity
    		if (retval==0)
    		{
    			printf("No activity .... clients : %d , phase : %d\n",nbClient,phase);
    
    		}
    		else
    		{
    			// Activity on the listening socket?
    			if (FD_ISSET (listenfd, &readfs))
    			{
    				printf("Incoming connection!\n");
    
    				// We accept a new connection
    				connfd[clientMax] = accept(listenfd, (struct sockaddr *) &clientInfos, &client_len);
    
    				// We update the maxdescriptor
    				if(connfd[clientMax]>maxdescriptor)
    					maxdescriptor=connfd[clientMax];
    
    				// New client is alive
    				clientAlive[clientMax]=1;
    
    				// We are going to send his id to him
    				sprintf_s(data,"%d",clientMax);
    				data_len=2;
    
    				// We add the client socket in write fd_set, to send him the data
    				FD_SET(connfd[clientMax],&writefs);
    
    				// We update the counter variables
    				clientMax++;
    				nbClient++;
    
    			}
    
    			// Activity on an alive client socket?
    			for(int i=0;i<clientMax;i++)
    			{
    				if(clientAlive[i]==0)
    					continue;
    
    				// Writing activity ?
    				if (FD_ISSET (connfd[i], &writefs))
    				{
    					// We send data to the client
    					send(connfd[i], data, data_len, 0);
    					
    					// We erase the socket from the writing fd_set
    					FD_CLR(connfd[i],&writefs);
    		
    					// If phase 3 is on :
    					if(phase==3 && start==0)
    					{
    						// Client i has started capturing
    						captureStarted[i]=1;
    						// We forge the phase 3 first packet of the client
    						data[0]=0x04;
    						data[1]=0x00;
    						// We send it
    						send(connfd[i], data, data_len, 0);
    						printf("First capture request sent to client %d\n",i);
    						// We reset data for the others non-started clients
    						data[0]=0x03;
    						data[1]=0x00;
    					}
    
    					// We check if all the clients are started
    					start=1;
    					for(int j=0;j<clientMax && start;j++)
    					{
    						if(clientAlive[j]==0)
    							continue;
    
    						start=start&&captureStarted[j];
    					}
    
    					continue;
    				}
    
    				// Reading activity ?
    				if (FD_ISSET (connfd[i], &readfs))
    				{
    					// We receive data
    					data_len=recv(connfd[i], data,255, 0);
    					
    					// If length < 0 it means that the client has gone offline
    					if(data_len<0)
    					{
    						printf("Client %d disconnected\n",i);
    
    						// We update the array
    						clientAlive[i]=0;
    
    						// We erase its socket from all the fd_sets
    						FD_CLR(connfd[i],&readfs);
    						FD_CLR(connfd[i],&writefs);
    
    						// We close the connection
    						shutdown(connfd[i],2);
    
    						// We update counter
    						nbClient--;
    						continue;
    					}
    					else
    					{
    						printf("Incoming data from client %d at time %d\n",i,clock());
    
    						// New capture received
    						captureReceived[i]=1;
    
    						// We check if all the clients capture have been received
    						captureNeeded=1;
    						for(int j=0;j<clientMax && captureNeeded;j++)
    						{
    							if(clientAlive[j]==0)
    								continue;
    
    							captureNeeded=captureNeeded&&captureReceived[j];
    						}
    						
    					}
    					
    				}
    
    			}
    
    		}
    
    		// We reset the Write fd_set
    		FD_ZERO(&writefs);
    
    	}
    Alors oui c'est vrai que je fait select sur 2 fd_set, un pour les recv, l'autre sur les send, en fait j'aurais pu me debrouiller autrement, et ne surveiller que le fd_set des read, et envoyer a la main mes requetes au lieu de passser par le select!

    Mon probleme est que comme on peut voir dans le code j'utilise le buffer data pour les lectures, et pour l'ecriture, si j'en utilise un pour recv, et un autre pour send, ca plante, alors peut etre qu'il y a une histoire d'initialisation qui est necessaire pour le buffer dont on va se servir en ecriture, que je n'ai pas fait !

    Enfin, le listenfd sert pour les demandes de connexions, et les connfd[i] sont les sockets deja ouverts entre les clients et mon serveur! Et tout ces sockets sont dans le meme fd_set, pour surveiller leur activité.

  9. #9
    Membre expérimenté
    Avatar de granquet
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    1 201
    Détails du profil
    Informations personnelles :
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 201
    Points : 1 421
    Points
    1 421
    Par défaut
    les threads en reseau, c'est interressant quand y'as enormement de monde a connecter (et/ou avec des gros traitements) avec un server multi-core
    generalement un systeme de pool de threads avec des select dedans (faudrais un jour que j'ai le courage de faire un article complet sur le dev reseau et les avantages//inconveniants de select() par rapport a d'autres solutions)

    sous windows tu ne peux faire select() que sur des sockets (vas comprendre leur logique ...)

    je met un bout de code a moi montrant une utilisation de select pour un server

    (la liste des clients est implémenté avec une liste chaînée)

    Code C : 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
     
    FD_SET (listener, &master);
     
     
    fdmax = listener;               
    read_fds = master;              
     
     
    while (select (fdmax + 1, &read_fds, NULL, NULL, NULL) != SOCKET_ERROR)
    {
    //on vide le contenu du buffer de reception
            memset (buf, 0, sizeof (buf));  
    //on regarde s'il n'y as pas de nouveau clients
            if (FD_ISSET (listener, &read_fds))
            {
     
                    addrlen = sizeof (remoteaddr);
                    if ((newfd =
                                            accept (listener,
                                                    (struct sockaddr *) &remoteaddr, &addrlen)) == SOCKET_ERROR)
                    {
                            perror ("accept");
                    }
                    else
                    {
    //tout s'est bien passé, on l'ajoute
                            idexplr = serv_add_cli (newfd, sentinelle);
                            FD_SET (newfd, &master);
                            if (newfd > fdmax)
                            {       
                                    fdmax = newfd;
                            }
                    }
            }
            for (idexplr = sentinelle->next_cli; idexplr != NULL;
                            idexplr = idexplr->next_cli)
            {
    //on fait le tour des clients existants
                    if (FD_ISSET (idexplr->fd, &read_fds))
                    {
                            if ((nbytes = recv (idexplr->fd, buf, sizeof (buf), 0)) > 0) 
                            {
    //traitement des data reçues
                                    if ((path = parser(buf)) != NULL)
                                    {
                                            printf("client: %s\n",path);
                                            if((fc = getfilecontent(path)) != NULL)
                                            {
                                                    send(idexplr->fd,fc,strlen(fc),0);
                                                    free(fc),fc=NULL;
                                            }
                                    }
                                    else
                                    {
                                            send(idexplr->fd,NACK,strlen(NACK),0);
                                    }
                            }
     
                            closesocket (idexplr->fd);
                            FD_CLR (idexplr->fd, &master);
    //dirty: modification de "l'iterateur" dans le for:
                            idexplr = serv_del_cli (idexplr, sentinelle);
                            continue;
                    }
            }
    //on reset le fdset (select modifie le fdset qu'on lui passe)
    read_fds = master;
    }
    perror ("select");
    exit (1);
    }

    ce bout de code est tiré d'un petit serv http vite fait (fait pour un DS de reseau)
    click my www
    ............|___
    ...................\
    .................._|_
    ..................\ /
    ..................."

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

Discussions similaires

  1. [C] Probleme avec socket client-serveur TCP
    Par LinuxUser dans le forum Réseau
    Réponses: 33
    Dernier message: 15/05/2007, 22h26
  2. Socket TCP: probleme avec select()
    Par LinuxUser dans le forum Réseau
    Réponses: 38
    Dernier message: 09/05/2007, 23h37
  3. [Reseau] probleme client/serveur TCP LInux
    Par jmjmjm dans le forum Réseau
    Réponses: 20
    Dernier message: 03/12/2006, 19h32
  4. Serveur TCP/IP Indy bloquant ?
    Par f6dqm1 dans le forum Web & réseau
    Réponses: 6
    Dernier message: 07/12/2004, 09h08
  5. [Concept]Concept d'un serveur TCP/IP
    Par Zc dans le forum Développement
    Réponses: 8
    Dernier message: 17/01/2003, 17h06

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