第一次使用select(),也许是一个基本问题?

时间:2010-06-10 15:49:59

标签: c sockets select client-server

我使用select()已经使用此服务器工作了几天。它的作用是,我有两个客户端阵列(一个是“供应商”,另一个是“消费者”),服务器的任务是检查供应商是否有东西要发送给消费者,以及如果是肯定的,发送它。

服务器的第二部分是,当消费者收到供应商的信息时,他们会向发送信息的相同供应商发送确认消息。

当客户端连接时,它被识别为“未定义”,直到它发送带有“供应商”或“消费者”一词的消息(西班牙语,因为我来自那里),当服务器将其放入正确的客户数组。

嗯,服务器在这里做的并不是很重要。重要的是,我正在使用两个不同的“for”循环来做两个部分,这就是我遇到问题的地方。当第一个用户连接到服务器(无论是供应商还是消费者)时,服务器会陷入第一个或第二个循环,而不是仅仅继续执行。因为这是我第一次使用select(),我可能会遗漏一些东西。你们能给我任何帮助吗?

提前多多感谢。

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

2 个答案:

答案 0 :(得分:1)

嗯,我认为你的逻辑是错的。它看起来应该更像这样(警告,未经测试的伪代码):

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
         [...]
      }
   }
}

请注意,要真正做到这一点,您需要将所有套接字设置为非阻塞I / O并能够处理部分读取和写入(通过将部分数据存储到关联的本地内存缓冲区中)与那个消费者/生产者一起,直到你有足够的数据来处理),否则你可能会调用recv()或send()块,这会阻止事件循环能够为任何其他消费者或生产者提供服务。理想情况下,你应该阻止的唯一地方是select()......每个其他呼叫都应该是非阻塞的。但是如果你想让事情变得简单,你可能会暂时使用阻塞I / O.

答案 1 :(得分:0)

您可以阅读介绍性tutorial 查看阻塞与非阻塞连接