我使用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;
}
}
}
}
}
答案 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 查看阻塞与非阻塞连接