2010-06-10 4 views
1

J'ai travaillé pendant quelques jours avec ce serveur en utilisant select(). Ce qu'il fait, c'est que j'ai deux groupes de clients (l'un est «fournisseurs», et l'autre est «consommateurs»), et la mission du serveur est de vérifier si les fournisseurs ont quelque chose à envoyer aux consommateurs, et En cas affirmatif, envoyez-le.Première utilisation de select(), peut-être une question de base?

La deuxième partie du serveur est que, lorsque les consommateurs ont reçu les informations des fournisseurs, ils envoient un message de confirmation aux mêmes fournisseurs qui ont envoyé les informations. Quand un client se connecte, il est reconnu comme "indéfini", jusqu'à ce qu'il envoie un message avec le mot "fournisseur" ou "consommateur" (en espagnol, car je suis de là), quand le serveur le met en le tableau de clients correct.

Eh bien, ce que fait le serveur n'est pas très important ici. Ce qui est important, c'est que je fais les deux parties avec deux boucles "for" différentes, et c'est là que je suis en train d'avoir des problèmes. Lorsque le premier utilisateur se connecte au serveur (qu'il s'agisse d'un fournisseur ou d'un consommateur), le serveur reste bloqué dans la première ou la deuxième boucle, au lieu de simplement poursuivre son exécution. Comme c'est la première fois que j'utilise select(), il me manque peut-être quelque chose. Pourriez-vous me donner un coup de main?

Merci beaucoup d'avance.

for(;;) 
{ 
    rset=allset; 
    nready=select(maxfd+1,&rset,NULL,NULL,NULL); 

    if (FD_ISSET(sockfd, &rset)) 
    { 
     clilen=sizeof(cliente); 
     if((connfd=accept(sockfd,(struct sockaddr *)&cliente,&clilen))<0) 
     { 
      printf("Error"); 
     } 

     IP=inet_ntoa(cliente.sin_addr); 
     for(i=0;i<COLA;i++) 
     { 
      if(indef[i]<0) 
      { 
       indef[i]=connfd; 
       IPind[i]=IP; 
       break; 
      } 
     } 

     FD_SET(connfd,&allset);  
     if(connfd > maxfd) 
     { 
      maxfd=connfd; 
     } 
     if(i>maxii) 
     { 
      maxii=i; 
     } 
     if(--nready<=0) 
     { continue; } 
    }// Fin ISSET(sockfd) 

    for(i=0;i<=maxii;i++) 
    { 
     if((sockfd1=indef[i])<0) 
     { continue; } //! 

     if(FD_ISSET(sockfd1,&rset)) 
     { 
      if((n=read(sockfd1,comp,MAXLINE))==0) 
      { 
       close(sockfd1); 
       FD_CLR(sockfd1,&allset); 
       indef[i]=-1; 
       printf("Cliente indefinido desconectado \n"); 
      } 
      else 
      { 
       comp[n]='\0'; 
       if(strcmp(comp,"suministrador")==0) 
       { 
        for(j=0;j<=limite;j++) 
        { 
         if(sumi[j]<0) 
         { 
          IPsum[j]=IPind[i]; 
          sumi[j]=indef[i]; 
          indef[i]=-1; 
          if(j>maxis) 
          { 
           maxis=j; 
          } 
          break; 
         } 
        } 
       } 
       else if(strcmp(comp,"consumidor")==0) 
       { 
        for(o=0;j<=limite;j++) 
        { 
         if(consum[o]<0) 
         { 
          IPcons[o]=IPind[i]; 
          consum[o]=indef[i]; 
          indef[o]=-1; 
          if(o>maxic) 
          { 
           maxic=o; 
          } 
          break; 
         } 
        } 
       } 

       if(--nready <=0) 
       { 
        break; 
       } 
      } 
     } 
    }//fin bucle for maxii 
    for(i=0;i<=maxis;i++) 
    { 
     if((sockfd2=sumi[i])<0) 
     { continue; } 

     if(FD_ISSET(sockfd2,&rset)) 
     { 
      if((n=read(sockfd2,buffer2,MAXLINE))==0) 
      { 
       close(sockfd2); 
       FD_CLR(sockfd2,&allset); 
       sumi[i]=-1; 
       printf("Suministrador desconectado \n"); 
      } 
      else 
      { 
       buffer2[n]='\0'; 
       for(j=0;j<=maxic;j++) 
       { 
        if((sockfd3=consum[j])<0) 
        { continue; } 
        else  
        { 
         strcpy(final,IPsum[i]); 
         strcat(final,":"); 
         strcat(final,buffer2); 
         write(sockfd3,final,sizeof(final)); 
         respuesta[i]=1; 
        } 
       } 
       break; // ? 
      } 
     } 
    }//fin for maxis 

    for(i=miniic;i<=maxic;i++) 
    { 
     if((sockfd4=consum[i])<0) 
     { continue; } 

     if(FD_ISSET(sockfd4,&rset)) 
     { 
      if((n=read(sockfd4,buffer3,MAXLINE))==0) 
      { 
       close(sockfd4); 
       FD_CLR(sockfd4,&allset); 
       consum[i]=-1; 
       printf("Consumidor desconectado \n"); 
      } 
      else 
      { 
       buffer3[n]='\0'; 
       IP2=strtok(buffer3,":"); 
       obj=strtok(NULL,":"); 
       for(j=0;j<100;j++) 
       { 
        if((strcmp(IPsum[j],IP2)==0) && (respuesta[j]==1)) 
        { 
         write(sumi[j],obj,sizeof(obj)); 
         miniic=i+1; 
         respuesta[j]=0; 
         break;       
        } 
       } 
      } 
     } 
    } 
+0

La mise en forme de votre code est très mauvaise. Beaucoup de lignes vides supplémentaires. Parfois, les {-brackets sont sur la même ligne que l'instruction de contrôle, parfois non. Parfois, vous n'avez pas de parenthèses du tout. La première façon d'améliorer votre programmation est d'appliquer un formatage cohérent. – abelenky

+0

J'ai reformaté votre code selon des dispositions plus communément acceptées. – abelenky

Répondre

0

Vous pouvez lire le look d'introduction tutorial à bloquer les connexions vs non-bloquant

+0

Je suis désolé pour le mauvais formatage. La première chose que j'ai essayé de faire est d'utiliser send() et recv() au lieu de read() et write(), mais ça ne marche pas tout à fait bien. Merci pour les réponses de toute façon. – darkletter

1

Hmm, je pense que votre logique est tout faux. Elle devrait ressembler à quelque chose comme cela (avertissement, non testé pseudo-code):

for (;;) 
{ 
    // First, set up the fd_sets to specify the sockets we want to be notified about 
    fd_set readSet; FD_CLR(&readSet); 
    fd_set writeSet; FD_CLR(&writeSet); 
    int maxFD = -1; 
    for (int i=0; i<num_consumers; i++) 
    { 
     if (consumer_sockets[i] > maxFD) maxFD = consumer_sockets[i]; 
     FD_SET(consumer_sockets[i], &readSet); 
     if (consumer_has_data_he_wants_to_send[i]) FD_SET(consumer_sockets[i], &writeSet); 
    } 
    for (int i=0; i<num_producers; i++) 
    { 
     if (producer_sockets[i] > maxFD) maxFD = producer_sockets[i]; 
     FD_SET(producer_sockets[i], &readSet); 
     if (producer_has_data_he_wants_to_send[i]) FD_SET(producer_sockets[i], &writeSet); 
    } 

    // Now we block in select() until something is ready to be handled on a socket 
    int selResult = select(maxFD+1, &readSet, &writeSet, NULL, NULL); 
    if (selResult < 0) {perror("select"); exit(10);} 

    for (int i=0; i<num_consumers; i++) 
    { 
     if (FD_ISSET(consumer_sockets[i], &readSet) 
     { 
     // There is some incoming data ready to be read from consumer_socket[i], so recv() it now 
     [...] 
     } 
     if (FD_ISSET(consumer_sockets[i], &writeSet) 
     { 
     // There is buffer space in consumer_socket[i] to hold more outgoing 
     // data for consumer_socket[i], so send() it now 
     [...] 
     } 
    } 
    for (int i=0; i<num_producers; i++) 
    { 
     if (FD_ISSET(&producer_sockets[i], &readSet) 
     { 
     // There is some data ready to be read from producer_socket[i], so recv() it now 
     [...] 
     } 
     if (FD_ISSET(producer_sockets[i], &writeSet) 
     { 
     // There is buffer space in producer_socket[i] to hold more outgoing 
     // data for producer_socket[i], so send() it now 
     [...] 
     } 
    } 
} 

Notez que pour vraiment faire cela correctement, vous aurez besoin de mettre toutes vos prises de non-blocage des E/S et être capable de gérer les lectures et les écritures partielles (en stockant les données partielles dans une mémoire tampon locale associée à ce consommateur/producteur, jusqu'à ce que vous ayez assez de données pour agir), sinon vous risquez d'avoir un appel à recv() ou send() block, ce qui empêcherait la boucle d'événement de pouvoir desservir l'un quelconque des autres consommateurs ou producteurs. Idéalement, le seul endroit où vous devriez bloquer est select() ... tous les autres appels devraient être non bloquants. Mais si vous voulez garder les choses simples pour commencer, vous pourrez peut-être vous en sortir en bloquant les E/S pendant un moment.

+0

Merci beaucoup pour votre réponse. Il est un peu déprimant de voir comment vous travaillez de quelques jours doit être jeté à la poubelle, mais il est bon de connaître la vérité. C'est dommage car lors de l'exécution du serveur, il semblait vraiment que j'étais proche de le finir. Votre petit exemple changerait-il beaucoup si j'utilisais read(), write() et blocking des sockets? Il s'agit de devoirs universitaires, et nous n'avons jamais utilisé de sockets non bloquantes ou d'E/S non bloquantes. C'est tout nouveau pour moi, et la date limite est en quelque sorte proche. – darkletter

+0

Sur Linux/Unix, de toute façon, recv()/read() et write()/send() sont équivalents (du moins lorsqu'ils sont utilisés sur des sockets réseau). En ce qui concerne l'utilisation des sockets de blocage/IO, vous pouvez l'essayer, mais c'est compliqué car si vous essayez de lire()/recv() sur un socket qui n'a pas de données à lire, alors read()/recv() ne reviendra pas jusqu'à ce que plus d'octets arrivent du réseau ...ce qui pourrait être long, ou jamais, et en attendant, toutes les autres E/S de socket sont bloquées. (il y a un problème similaire avec le blocage de send()/write() si le client distant refuse de lire ses données entrantes, mais ce n'est pas un problème aussi important). –