linux下面select返回115错误

或者你会发现,你在编写程序时,不注意,或者一个很不起眼的写法,可它会给你带来很无奈的错误,让你很久才会发现,原来这个问题是这么回事。

1、常见的写法问题

1
2
3
4
5
6
7
8
9
fd_set fd;
FD_ZERO(&fd);
FD_SET( skt, &fd);
do
{
   int n = select( skt+1, &fd, 0,0, 0);
   if ( n == -1 ) break ;
   else if ( n > 0) break ;
} while ( true );

这个问题看似不怎么,根据原理select会重置参数,所以fd这个参数在调用完select之后会被更改,所以下次执行select必须重新设置fd,就是说要将 FD_ZERO(&fd); FD_SET( skt, &fd);放在do,while里面,即每次select都要先初始化fdset;

2、另外做超时时可能会出现115错误,linux下面使用常见错误,这个问题我也遇到过,发现是一个很犀利的写法

select最后一个参数是timeval指针,这个指针也需要和fd一样,在每次select都要重新设置,如下面代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//ERROR
timeval tv; tv.sec = 0;tv.usec = 10;
do
{
    fd_set fd; FD_ZERO(&fd); FD_SET(skt,&fd);
  int n =  select( skt + 1, &fd, 0,0, &tv ); //执行完这句tv就被置0了
  if ( n ==-1 || n>0) break ;
} while ( true );
//OK
do
{
    timeval tv; tv.sec = 0;tv.usec = 10;
    fd_set fd; FD_ZERO(&fd); FD_SET(skt,&fd);
  int n =  select( skt + 1, &fd, 0,0, &tv ); //执行完这句tv就被置0了
  if ( n ==-1 || n>0) break ;
} while ( true );

这是我在写一个超时计算代码时发现的问题,有一个函数发送数据,需要在指定的时间内发送完,如果超过时间就返回真实发送长度。

那么,你可能需要在多次send之间来计算哪些是超时的,假如我传一个30秒的超时,你不能只select一次,将时间设置为超时,因为这样有问题,就是在第一次select成功之后,在send的时候可能没有发送完所有数据,还要不断的发送,在再次发送时超时就不好计算了,因为你上次select用的30秒,把时间用光了,并且你也不知道select到底用了多少时间。

我们可以将30秒划分为几个小的秒单位,比较每次select用1秒的时间,这样每次select或send超时都计1秒时间 ,在不断的累加就可以了。刚好在累加的时候如果你把timeval参数写在 do,while外面

那么只有第一次是正常的,第二次timeval变成 tv.sec = 0,tv.usec = 0;这样会造成select超时计算失误,因为tv值0表示不等待直接返回,假如此时发送缓冲已满,立马返回超时,这样你累加1秒时间就不准。

 

我当时测试 的是,设置30秒,结果只等 了一秒就返回超时了,打印日志显示select返回0确实是有30次,可是除了第一次有延迟,后面的基本上是同时显示出来的,就说明后面select根本没有等待,后来发现这个timeval被置0了,我呢个去,不发现不知道,一发现太肯我了。

除声明外, 跑步客文章均为原创,转载请以链接形式标明本文地址

本文地址:   http://www.paobuke.com/develop/c/pbk1371.html

你可能感兴趣的:(linux下面select返回115错误)