为什么select之前都要FD_ZERO()?



while(1)
 { 
  FD_ZERO(&readfds); 
  FD_SET(sockfd,&readfds); 

  for(fd=0;fd<MAXSOCKFD;fd++) 
   if(is_connected[fd]) FD_SET(fd,&readfds); 

  //fcntl(sockfd, F_SETFL, O_NONBLOCK)实现了非阻塞接收信息,select()解决了终端的阻塞问题
  if(!(nready = select(MAXSOCKFD,&readfds,NULL,NULL,NULL)))continue; 

  for(fd=0;fd<MAXSOCKFD;fd++) 
  {
   if(FD_ISSET(fd,&readfds))
   { 
    if(sockfd == fd)
    { 
     if((newsockfd = accept (sockfd,&addr,&addr_len))<0) 
      perror(“accept”); 
     write(newsockfd,msg,sizeof(msg)); 
     is_connected[newsockfd] =1; 
     printf(“cnnect from %s\n”,inet_ntoa(addr.sin_addr)); 
    }
    else
    { 
     bzero(buffer,sizeof(buffer)); 
     if(read(fd,buffer,sizeof(buffer))<=0)
     { 
      printf(“connect closed.\n”); 
      is_connected[fd]=0; 
      close(fd); 
     }
     else 
      printf(“%s”,buffer); 
    }     
    if(--nready <= 0)
     break;
   }
  }
 } 

-----------------------------------------------------------------------

 FD_ZERO(&readfds); 
 while(1)
 { 
  FD_SET(sockfd,&readfds); 

  for(fd=0;fd<MAXSOCKFD;fd++) 
   if(is_connected[fd]) FD_SET(fd,&readfds); 

  //fcntl(sockfd, F_SETFL, O_NONBLOCK)实现了非阻塞接收信息,select()解决了终端的阻塞问题
  if(!(nready = select(MAXSOCKFD,&readfds,NULL,NULL,NULL)))continue; 

  for(fd=0;fd<MAXSOCKFD;fd++) 
  {
   if(FD_ISSET(fd,&readfds))
   { 
    if(sockfd == fd)
    { 
     if((newsockfd = accept (sockfd,&addr,&addr_len))<0) 
      perror(“accept”); 
     write(newsockfd,msg,sizeof(msg)); 
     is_connected[newsockfd] =1; 
     printf(“cnnect from %s\n”,inet_ntoa(addr.sin_addr)); 
    }
    else
    { 
     bzero(buffer,sizeof(buffer)); 
     if(read(fd,buffer,sizeof(buffer))<=0)
     { 
      printf(“connect closed.\n”); 
      is_connected[fd]=0;
      FD_CLR(fd, readfds); 
      close(fd); 
     }
     else 
      printf(“%s”,buffer); 
    }     
    if(--nready <= 0)
     break;
   }
  }
 } 

 

上面的代码将FD_ZERO放在循环里面,下面的代码将FD_ZERO放在外面,但是有FD_CLR。二者有什么不一样么?我咋觉得第二种效率更高?
为什么设计良好的代码应该永远不使用FD_CLR,而且实际情况中它也确实很少被使用?
我来帮他解答
满意回答
FD_ZERO宏完成的工作就是一个初始化套接字集合(其实就是清空套接字集合),就你给出的程序而言,FD_ZERO在循化外循环内都是一样的。不过一般来讲,初始化服务端的所有套接字组成的集合就应该把FD_ZERO放在循环外,而初始化具有可读或者可写属性的套接字集合就应该把FD_ZERO放在循环内部。因为服务端一旦启动服务线程,就会一直处于循环状态,每一次循环完成都应该将具有可读可写属性的套接字集合清空。
FD_CLR宏是用来从套接字集合中删除指定的套接字,调用方式为FD_CLR(s,*set);该宏会把被清除的套接字之后的所有套接字在数组中依次向前移动一个位置(这就是它实现删除套接字的原理),如果你在后面执行其它删除套接字的函数时稍不小心就可能会删除掉处于正常状态的套接字,因为你不一定能对套接字集合中的套接字下标做到了如指掌。所以良好的设计风格应该避免使用FD_CLR宏。
个人意见,仅供参考,如果有误,还请谅解!

你可能感兴趣的:(为什么select之前都要FD_ZERO()?)