views:

106

answers:

3

Hello people, i've been working for a few days with this server using select(). What it does, is that, i have two arrays of clients (one is "suppliers", and the other is "consumers"), and the mission of the server is to check whether the suppliers have something to send to the consumers, and in case affirmative, send it.

The second part of the server is that, when the consumers have received the suppliers' info, they send a confirmation message to the same suppliers that sent the info.

When a client connects, it gets recognized as "undefined", until it sends a message with the word "supplier" or "consumer" (in Spanish, as i'm from there), when the server puts it in the correct clients array.

Well, what the server does is not very important here. What's important is that, i'm doing both parts with two different "for" loops, and that's where i'm getting the problems. When the first user connects to the server (be it a supplier or a consumer), the server gets stuck in the first or second loop, instead of just continuing its execution. As it's the first time i'm using select(), i may be missing something. Could you guys give me any sort of help?

Thanks a lot in advance.

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;                           
                    }
                }
            }
        }
    }
A: 

You might read the introductory tutorial Look at blocking vs non-blocking connections

Jay
I am sorry for the poor formatting. The first thing i've tried to do is to use send() and recv() instead of read() and write(), but still it doesn't quite work ok. Thanks for the replies anyways.
darkletter
A: 

Hmm, I think your logic is all wrong. It should look something more like this (warning, untested 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
         [...]
      }
   }
}

Note that to really do this properly, you'd need to set all of your sockets to non-blocking I/O and be able to handle partial reads and writes (by storing the partial data into a local memory-buffer associated with that consumer/producer, until you have enough data to act on), otherwise you risk having a call to recv() or send() block, which would prevent the event loop from being able to service any of the other consumers or producers. Ideally the only place you should ever block in is select()... every other call should be non-blocking. But if you want to keep things simple to start out with, you may be able to get away with using blocking I/O for a while.

Jeremy Friesner
Thanks a lot for your answer. It is kind of depressing to see how you work of some days has to be thrown into the bin, but it's good to know the truth. It's a shame because when executing the server it really seemed i was close to finishing it. Would your little example change much if i used read(), write(), and blocking sockets? This is college homework, and we've never used either non-blocking sockets or non-blocking I/O. This is all new to me, and the deadline is somehow near.
darkletter
On Linux/Unix, anyway, recv()/read() and write()/send() are equivalent (at least when they are used on network sockets). As far as using blocking sockets/IO goes, you can try it, but it's tricky because if you ever try to read()/recv() on a socket that has no data ready to read, then read()/recv() will not return until more bytes arrive from the network... which could be a long time, or never, and in the meantime, all other socket I/O is blocked. (there's a similar issue with send()/write() blocking if the remote client refuses to read its incoming data, but it's not quite as big a problem).
Jeremy Friesner
A: 

Thanks for the insight Jeremy, tomorrow i will ask the professor whether it's compulsory or not to use blocking sockets (he never explained to us non-blocking sockets, so i suppose it will be compulsory), but if not, i will proceed to investigate the non-blocking way.

Thanks a lot

PS: Thanks for the formatting abelenky.

darkletter