日期:2014-05-16  浏览次数:20574 次

select函数不起作用
主体架构都基本正确(以前使用两个while死循环,能正确传送),现在该成一个while死循环加select函数遇到以下情况:
  注:因为传送的文件比较大,所以需要多次接收和发送。连接一次后,用while循环实现,不需要每次传接都连接。

1,当时间设为“0”和NULL时,可以收到并发送1个包,服务器第二次收发时,好像就卡在select函数一样,既不返回错,也不继续往下执行(此时客户端还是使用的两个死循环,它显示发给服务器端的第2个数据包已正确发送),

2,当时间设定为2.5S时,可以收到并发送1个包,服务器第二次收发时,select函数的返回值一直为0,一直循环判断select函数(此时客户端还是使用的两个死循环,它显示发给服务器端的第2个数据包已正确发送),
  如果此时如果将select返回0的情况注释掉,可以连续的传接数据,知道文件完,但是,每次收发数据都必须等到设定的时间过了之后才行,相当于sleep了设定的秒数。 

//服务器程序
int main()
{
  ...............................

while(1)
{
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET(ser_sockfd,&rset);
FD_SET(ser_sockfd,&wset);
maxfd=ser_sockfd+1;
// timeout.tv_sec=2;
// timeout.tv_usec=500000;

for(cyc=0;cyc<LISTEN_QUEUE_NUM;cyc++)
{
if(fd_A[cyc]!=0)
{
printf("fd_A[%d] added into the select list\n",cyc);
added_fd++;
}
}

if( (ret=select(maxfd,&rset,&wset,(fd_set*)NULL,(struct timeval*)NULL)) <0)
{
perror("wrong select\n");
return(-1);
}

else if(ret==0)
{
printf("selecting and waiting\n");
continue;
}
if( (FD_ISSET(ser_sockfd,&rset))|| (FD_ISSET(ser_sockfd,&wset)) )
{
int len_2=sizeof(cliaddr);
if((nsock= accept(ser_sockfd ,(struct sockaddr *)&cliaddr,(uint32_t *)&len_2) )<=0)
{
perror("ERROR on accept\n");
continue;
}
  if (added_fd < LISTEN_QUEUE_NUM)
  {
  fd_A[added_fd] = nsock;
  if(nsock>maxfd)
{
maxfd=nsock+1;
}
  }
  else
  {
printf("max connections arrived,exit\n");
close(nsock);
break;
  }

  }
for(cyc=0;cyc<LISTEN_QUEUE_NUM;cyc++)
{
if(fd_A[cyc]!=0)
{
FD_SET(fd_A[cyc],&rset);
FD_SET(fd_A[cyc],&wset);
}
}

  for(cyc=0;cyc<=maxfd;cyc++)
  {
if(FD_ISSET(fd_A[cyc],&rset))
  {
  读操作//这个应该正确
  }
if(FD_ISSET(fd_A[cyc],&rset))
  {
  写操作//这个应该正确

  }
  }
  }
 
  for (cyc = 0; cyc < LISTEN_QUEUE_NUM; cyc++)
  {
  if (fd_A[cyc] != 0)
  {
  close(fd_A[cyc]);
  }
  }
  close(ser_sockfd);
  return ( 0);
}

------解决方案--------------------
每次循环时,你都将rset和wset清空了,然后只添加一个ser_sockfd,并未添加fd_A。那你在select时rset和wset也就只有ser_sockfd了。
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET(ser_sockfd,&rset);
FD_SET(ser_sockfd,&wset);

------解决方案--------------------
select返回后会把你的rset和wset都设置成准备好的文件描述符,如果超时,那rset和wset都清空了,如果下次还需要检查就要重新设置rset和wset,相信你改过了之后就没有问题了!