最近写代码写到非阻塞IO的时候用到的select函数,这里简单记录一下用法~~~~~(不记录着实容易忘啊)
一、头文件&原型
头文件include<sys/select.h>
原型:源码里的原型张这个样子咯!

第一个参数__nfds:最大文件描述符加1,因为文件描述符编号从0开始,所以要在最大文件描述符编号值上加1;
中间三个参数readfds、writefds、exceptfds:我们所关心的可读、可写或者异常的文件描述符集合;
最后一个参数timeout三种情况:
1、NULL:无限期等待直到所指定的文件描述符有一个准备好了或者捕捉到一个信号,如果是捕捉一个信号则会反回-1并将erron设置成EINTR,错误码啥意思?一定要学会查linux源码,会告诉你错在哪了。看图:这个意思就是中断系统调用咯,因为select本身就是一个系统调用。

2、等于0:压根不去等待,将所有指定的描述符轮询一遍就返回了
3、不等于0:等待指定的时间,有文件描述符准备好或者超时就返回,如果是超时则返回0。当然这个也可以像第一种情况一样被捕捉到的信号打断。
二、为什么要用select函数
linux网络编程要搞一个非阻塞的socket,所以就用咯!用在connect和recv;
当然select还有一个很巧妙的用法,就是精确的延时,我们知道sleep()是秒级的,那想要毫妙级的怎么办,当然自己写一个了
void Sleep(int nMilSeconds)
{
struct timeval t;
t.tv_sec= nMilSeconds/1000;
t.tv_usec= nMilSeconds%1000*1000;
select(0,NULL,NULL,NULL,&t);
}
三、fd_set
用select当然少不了fd_set啦!fd_set是个什么鬼,如果我没找错,它应该长这样

这个玩意占128个字节,每一个位控制一个文件描述符,那总共就可以控制1024个文件描述符,一般也用不到那么多滴!
操作fd_set的函数有这么几个

第一个是个宏定义,也就是上面算的1024
FD_SET():将你想监控的文件描述符添加到集合里;
FD_CLR():当然就是清除一位了;
FD_ISSET():检测某个文集描述符是否有效,然后做相应的操作;
FD_ZERO():将集合清零,每次用的时候清一下还是有必要的;
四、简单用法
看前辈写的一段代码,我若有所思~~~~看一段connect时源码,关于这段代码你有什么想法???欢迎评论!
int connect_nonblock(const char* lpIP, int nPort)
{
int err = -1, len = 0;
struct timeval tm;
fd_set set;
unsigned long ul = 1;
bool ret = false;
struct sockaddr_in SockAddress;
SOCKET hLocalSocket;
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = htons(nPort);
SockAddress.sin_addr.s_addr=inet_addr(lpIP);
memset(SockAddress.sin_zero, 0, sizeof(SockAddress.sin_zero));
ioctl(hLocalSocket, FIONBIO, &ul);
if(-1 == connect(hLocalSocket, (struct sockaddr *)&SockAddress, sizeof(struct sockaddr_in)))
{
tm.tv_sec = TIME_OUT_TIME;
tm.tv_usec = 0;
FD_ZERO(&set);
FD_SET(hLocalSocket, &set);
if( (select(hLocalSocket+1, NULL, &set, NULL, &tm)) > 0)
{
getsockopt(hLocalSocket, SOL_SOCKET, SO_ERROR, &err, (soc

本文介绍了Linux编程中的select函数,包括其头文件、原型及参数含义。重点讲解了函数的使用场景,如非阻塞IO、精确延时,并通过示例代码展示了如何在connect和recv中应用。同时,文章提到了fd_set的使用和相关操作函数,以及在实际编程中需要注意的问题,如错误码EINPROGRESS的判断。
最低0.47元/天 解锁文章
1385

被折叠的 条评论
为什么被折叠?



