select执行正常,为什么有时FD_ISSET却判断失败

疯疯癫癫 2012-07-10 09:52:55
问题是这样的,select执行后,有时FD_ISSET却判断失败,但大部分的时候都是判断正常的,判断失败的情况大概执行100次会出现6次,但是现在不允许FD_ISSET判断失败,我想问下,标题所示的这种情况是在什么条件下发生的。
下面是相关源码:


int recv_data(int sockfd)
{
fd_set r_set;

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

if(select(sockfd + 1, &r_set, NULL, NULL, NULL) == -1)
err_sys("select error \n");
// 当我描述的问题出现时,可以执行到这里,可是下面有时判断失败
if(FD_ISSET(sockfd, &r_set))
{
// do something
}
}
return 1;
}


我的环境是Linux。。。。。。
...全文
1043 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
matthklo 2013-02-19
  • 打赏
  • 举报
回复
最近同樣也遇到了這個問題, 最後推測的可能原因是客戶端連線數量太多了, 導致 sockfd 具體數字超過了 FD_SET 能表達的上限 (1024). 依照 man page 的解釋這種行為下的結果是未定義的. An fd_set is a fixed size buffer. Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will result in undefined behavior. Moreover, POSIX requires fd to be a valid file descriptor. 我的作法是改以 poll/epoll 實現
疯疯癫癫 2012-07-23
  • 打赏
  • 举报
回复
我还是没有找到问题的根本所在,先结贴。。。
疯疯癫癫 2012-07-13
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 的回复:]
这个还真的没遇到过,阻塞状态的超时设置不是应该为null么?
[/Quote]
嗯,设置为NULL等不到准备好的描述符会一直阻塞(一直等待让我的程序卡在select那里。。。。),我更改后只让它阻塞设定的秒数
疯疯癫癫 2012-07-13
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 的回复:]
不是啊!你要接收数据,自然要确定有人在给你发数据啊,另外你的sockfd是如何生成和配置的?
[/Quote]
另一块大概是这样的

int function()
{
//父进程中
int sockfd = 0;
int SNDBUF = 204800; //发送缓冲区
int RCVBUF = 204800; //接收缓冲区
if ((sockfd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) == -1)
printmsg("create socket error");
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //非阻塞
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &SNDBUF, sizeof(SNDBUF)) == -1)
printmsg ("setsockopt error\n");
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &RCVBUF, sizeof(RCVBUF));

//............一些其他的操作
while(1)
{
if(数据未读取)
{
//do something
continue;
}
if(接收数据)
{
recv_data(sockfd);
}
}
printmsg("function is over.....\n");
return 0;
}
dongjiawei316 2012-07-13
  • 打赏
  • 举报
回复
不是啊!你要接收数据,自然要确定有人在给你发数据啊,另外你的sockfd是如何生成和配置的?
疯疯癫癫 2012-07-13
  • 打赏
  • 举报
回复
回复18楼,是说 int recv_data(int sockfd)中的sockfd有值么?
dongjiawei316 2012-07-13
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]
引用 14 楼 的回复:
但你无法凭借“没有打印信息”就确定select执行成功了啊!

嗯,我刚才将select最后一个参数改了,不让它永久等待,详细描述请看注释。。。。

C/C++ code


int recv_data(int sockfd)
{
fd_set r_set;
struct timeval tv;

while(1)
……
[/Quote]
那就是说select并没有正确返回。。。。你确定你在给它发流吗?
疯疯癫癫 2012-07-12
  • 打赏
  • 举报
回复
程序出于某种要求,这个函数必须为永远等待,所以select函数的最后一个参数我写成了NULL
[Quote=引用 11 楼 的回复:]
你的select没有超时退出的时间限制,所以我觉得可能是select没有返回
[/Quote]
疯疯癫癫 2012-07-12
  • 打赏
  • 举报
回复
问大家一下

sockfd = 5; //如果sockfd的值等于5
//那么FD_ISSET判断成功时,r_set.__fds_bits[5]的值是不是应该为 1
dongjiawei316 2012-07-12
  • 打赏
  • 举报
回复
你的select没有超时退出的时间限制,所以我觉得可能是select没有返回
dongjiawei316 2012-07-12
  • 打赏
  • 举报
回复
汗,
1、你的代码为什么不写成
   ret = select(sockfd + 1, &r_set, &w_set, NULL, NULL);
if(ret == -1)
{
}
else if(ret == 0){

}
else{
printmsg("select ok !\n");//确定select成功了返回了

}
LittleNumb 2012-07-12
  • 打赏
  • 举报
回复
这个还真的没遇到过,阻塞状态的超时设置不是应该为null么?
疯疯癫癫 2012-07-12
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 的回复:]
但你无法凭借“没有打印信息”就确定select执行成功了啊!
[/Quote]
嗯,我刚才将select最后一个参数改了,不让它永久等待,详细描述请看注释。。。。

int recv_data(int sockfd)
{
fd_set r_set;
struct timeval tv;

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

tv.tv_sec = 3; //如果问题出现了,这里时间无论我设置的大一些或者小一些,下面会一直超时
tv.tv_usec = 0;

int ret = select(sockfd + 1, &r_set, NULL, NULL, &tv);
if( ret == -1){
perror("select");
break;
}else if(ret == 0)
{
printmsg("Timeout!\n");
continue;
}
if(FD_ISSET(sockfd, &r_set))
{
// do something
}
}
return 1;
}
dongjiawei316 2012-07-12
  • 打赏
  • 举报
回复
但你无法凭借“没有打印信息”就确定select执行成功了啊!
疯疯癫癫 2012-07-11
  • 打赏
  • 举报
回复
额,注释信息比较长。。。请拖动滚动条查看我描述的问题

我以为会自动换行的。。。。
疯疯癫癫 2012-07-11
  • 打赏
  • 举报
回复

int recv_data(int sockfd)
{
printmsg("I'm in recv_data Funtion !\n"); //当我描述的问题出现时,只输出了这句打印,下面的select判断出错信息都没有输出,可见执行到这里时select判断没有问题,但是为什么有时FD_ISSET却判断失败?
fd_set r_set;

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

if(select(sockfd + 1, &r_set, &w_set, NULL, NULL) == -1){
perror("select");
break;
}else if(select(sockfd + 1, &r_set, &w_set, NULL, NULL) == 0)
{
printmsg("Timeout !\n");
continue;
}
if(FD_ISSET(sockfd, &r_set))
{
printmsg("recv data packet...\n"); //回复6楼,通过这句打印信息来判断的
// do something
}
}
return 1;
}

感谢楼上几位的回复,怪我没描述清,上面是我修改后的代码。我的具体问题在代码注释
qq120848369 2012-07-11
  • 打赏
  • 举报
回复
你的代码逻辑告诉我,无论select返回什么,你都会去判断FD_ISSET, 这怎么会合理呢。
jialejiahi 2012-07-11
  • 打赏
  • 举报
回复
// 当我描述的问题出现时,可以执行到这里,可是下面有时判断失败
这句话后面有没有做什么操作导致后面判断失败?
你怎么证明判断失败的?可否把代码贴一下?
疯疯癫癫 2012-07-10
  • 打赏
  • 举报
回复 1
刚刚我加入select返回0的语句调试了下,当我所描述的问题出现时,并非是由超时引起的。

请问是否还有其他的可能原因?
[Quote=引用 1 楼 的回复:]
原因是:
有时select会超时退出,返回0,这种情况下r_set会被清零。所以FD_ISSET失败。

因此:
你加上对select返回0的处理就可以了。
[/Quote]
dongjiawei316 2012-07-10
  • 打赏
  • 举报
回复
原因是:
有时select会超时退出,返回0,这种情况下r_set会被清零。所以FD_ISSET失败。

因此:
你加上对select返回0的处理就可以了。
加载更多回复(3)

23,120

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧