1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > select函数到底该怎么用?

select函数到底该怎么用?

时间:2022-11-07 00:37:25

相关推荐

select函数到底该怎么用?

大家好,我是涛哥。

中秋节刚刚过去,大家过得挺开心吧。关于中秋,有很多美好的诗词歌赋,也有很多形式的纪念,比如孔明灯。我自己没去放孔明灯,仅手绘一张,聊寄我思。

涛哥手绘(临摹)

欢乐时光,总是短暂。又是上班的节奏了,是该收收心咯。接下来,我们来看看重要的select函数,建议有兴趣的朋友亲自运行并调试一下程序,肯定会有收获。

一. 关于select函数

select函数是什么呢?为什么这么重要?熟悉网络编程的朋友,肯定听说过select函数,而且在笔试面试中经常和poll、epoll做比较,屡考不厌。

无论是Windows还是Linux中的网络编程,都会涉及select函数,大同小异,本文以Linux中的select为范例来介绍,先来看select函数的介绍:

DESCRIPTIONselect() and pselect() allow a program to monitor multiple file descriptors, waiting until one or more of the filedescriptors become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered readyif it is possible to perform a corresponding I/O operation (e.g., read(2) without blocking, or a sufficiently smallwrite(2)).

可见,select函数可以用来监控多个文件描述符的状态。请注意,这里文件描述符可以是标准输入标准输出,也可以是网络套接字,它们都是广义的文件描述符。

二. 监控标准输入

接下来,我们看看select函数监控标准输入的实战,程序如下:

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<unistd.h>#include<sys/time.h>#include<sys/types.h>int main(){struct timeval tv; // 超时时间tv.tv_sec = 10;tv.tv_usec = 500;// 注意单位是微秒fd_set rdfds;FD_ZERO(&rdfds);// 描述集初始化FD_SET(STDIN_FILENO, &rdfds); // STDIN_FILENO是标准输入,塞入描述集int iRet = select(STDIN_FILENO + 1, &rdfds, NULL, NULL, &tv); // 第一个参数是监控句柄号+1if(iRet < 0){printf("selcet error, iRet %\n", iRet);return -1;}if(0 == iRet){printf("timeout \n");return -2;}printf("iRet = %d \n", iRet); // 在终端中输入,然后按enter,会走到这里char szBuf[10]= {0};if(FD_ISSET(STDIN_FILENO, &rdfds) )// 监控输入描述符已经发生了改变{ printf("to read data\n");read(STDIN_FILENO, szBuf, sizeof(szBuf) - 1); // 从键盘读取输入}write(STDOUT_FILENO, szBuf, strlen(szBuf)); // 在终端中回显return 0;}

执行程序后,卡在select处,如果不输入任何东西,那么会在10秒+500微秒时,select返回0,这个特性可以用来做延时函数。

如果在超时之前输入,那么select函数立即返回1,因为select监控到标准输入描述符有可读信息,立刻能感知到描述符的状态。

三. 监控标准输出

为了更好地理解上面的程序,我们继续来看一个有趣的问题,程序如下:

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<unistd.h>#include<sys/time.h>#include<sys/types.h>int main(){struct timeval tv; // 超时时间tv.tv_sec = 10;tv.tv_usec = 500;// 注意单位是微秒fd_set rdfds;FD_ZERO(&rdfds);// 描述集初始化FD_SET(STDIN_FILENO, &rdfds); // STDIN_FILENO是标准输入, 塞入描述集FD_SET(STDOUT_FILENO, &rdfds); // STDOUT_FILENO是标准输入, 塞入描述集if(FD_ISSET(STDIN_FILENO,&rdfds)){printf("STDIN_FILENO is in fds 111\n");}if(FD_ISSET(STDOUT_FILENO,&rdfds)){printf("STDOUT_FILENO is in fds 222\n");}int iRet = select(STDIN_FILENO + 1, &rdfds, NULL, NULL, &tv); // 第一个参数是监控句柄号+1if(iRet < 0){printf("selcet error, iRet %\n", iRet);return -1;}if(0==iRet){printf("timeout \n");}printf("iRet = %d \n", iRet);if(FD_ISSET(STDIN_FILENO,&rdfds)){printf("STDIN_FILENO is in fds 333\n");}if(FD_ISSET(STDOUT_FILENO,&rdfds)){printf("STDOUT_FILENO is in fds 444\n");}return 0;}

运行程序,然后什么也不要动,安静地等到超时,程序的结果为:

STDIN_FILENO is in fds 111STDOUT_FILENO is in fds 222timeout iRet = 0

可见,刚开始时,标准输入输出描述符都在描述集中。在超时时间内,没有检测到输入输出,两个描述集被自动清除。

如果再次运行上述程序,并在10s+500微秒的超时时间内输入数据,此时不会有timeout超时现象,可以看到的结果为:

STDIN_FILENO is in fds 111STDOUT_FILENO is in fds 222iRet = 1 STDIN_FILENO is in fds 333

可见,检测到有输入后,select函数立即返回,此时标准输入描述符仍然在描述集中,而标准输出描述集则被清除。所以,在调用select之前,通常需要把待监测的描述符放到描述集中。

然而,在调用select之后,用FD_ISSET可以检测哪些描述符仍在描述集中,那么这些描述集就处于就绪状态,故select前后的操作均不可少。因此,使用select时的建议编程范式如下:

FD_ZERO

FD_SET

select

FD_ISSET

上述iRet为1表示rdfds中,就绪的描述符总个数为1.本文例子是使用select函数监控标准输入输出描述符,至于监控网络套接字,也是类似。后面会逐渐聊到网络编程的实战,敬请期待。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。