Select模型函数详解
Select模型原理
利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据。目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据,被迫进入阻塞状态。
Select函数介绍
select参数和返回值意义如下:
int select (
IN int nfds, //0,无意义
IN OUT fd_set* readfds, //检查可读性
IN OUT fd_set* writefds, //检查可写性
IN OUT fd_set* exceptfds, //例外数据
IN const struct timeval* timeout); //函数的返回时间
struct timeval {
long tv_sec; //秒
long tv_usec; //毫秒
};
对于
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
第一个参数 nfds: 第n个文件id的编号 (linux下,一切皆文件) 需要注意的是: nfds = fd+1 (fd 为 FD_SET中的fd)
第二个参数: fd_set *readfds 读取文件编号,如果不需要读取的话 可以设置为NULL
第三 ,四个参数: 同上
第五个参数:为一个定义超时的结构体
select返回fd_set中可用的套接字个数。
fd_set是一个SOCKET队列,以下宏可以对该队列进行操作:
1:FD_CLR( s, *set) 从队列set删除句柄s;
2:FD_ISSET( s, *set) 检查句柄s是否存在与队列set中;
3:FD_SET( s, *set )把句柄s添加到队列set中;
4:FD_ZERO( *set ) 把set队列初始化成空队列.
关于FD_CLR和FD_ZERO这两个函数,刚开始接触的时候,一直感觉区别不大,执行一个即可,但是在正在使用中发现这个两个意义完全不一样的函数,区别如下:
1:Select函数中的fd_set参数维护着一个可读性检查队列或者可写性检查队列。
2:FD_SET,FD_ISSET,FD_CLR分别是对加入队列中的套接字句柄进行添加,判断和删除操作。
3:FD_ZERO这个函数是在套接字加入队列之前,对队列初始化为0。
4:FD_ZERO是将整个队列清零,FD_CLR只是删除队列中某个对应的套接字
Select工作流程
1:用FD_ZERO宏来初始化我们感兴趣的fd_set。
也就是select函数的第二三四个参数。
2:用FD_SET宏来将套接字句柄分配给相应的fd_set。
如果想要检查一个套接字是否有数据需要接收,可以用FD_SET宏把套接接字句柄加入可读性检查队列中
3:调用select函数。
如果该套接字没有数据需要接收,select函数会把该套接字从可读性检查队列中删除掉,
4:用FD_ISSET对套接字句柄进行检查。
如果我们所关注的那个套接字句柄仍然在开始分配的那个fd_set里,那么说明马上可以进行相应的IO操 作。
比如一个分配给select第一个参数的套接字句柄在select返回后仍然在select第一个参数的fd_set里,那么说明当前数据已经来了, 马上可以读取成功而不会被阻塞。
Select模型原理
利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据。目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据,被迫进入阻塞状态。
Select函数介绍
select参数和返回值意义如下:
int select (
IN int nfds, //0,无意义
IN OUT fd_set* readfds, //检查可读性
IN OUT fd_set* writefds, //检查可写性
IN OUT fd_set* exceptfds, //例外数据
IN const struct timeval* timeout); //函数的返回时间
struct timeval {
long tv_sec; //秒
long tv_usec; //毫秒
};
对于
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
第一个参数 nfds: 第n个文件id的编号 (linux下,一切皆文件) 需要注意的是: nfds = fd+1 (fd 为 FD_SET中的fd)
第二个参数: fd_set *readfds 读取文件编号,如果不需要读取的话 可以设置为NULL
第三 ,四个参数: 同上
第五个参数:为一个定义超时的结构体
select返回fd_set中可用的套接字个数。
fd_set是一个SOCKET队列,以下宏可以对该队列进行操作:
1:FD_CLR( s, *set) 从队列set删除句柄s;
2:FD_ISSET( s, *set) 检查句柄s是否存在与队列set中;
3:FD_SET( s, *set )把句柄s添加到队列set中;
4:FD_ZERO( *set ) 把set队列初始化成空队列.
关于FD_CLR和FD_ZERO这两个函数,刚开始接触的时候,一直感觉区别不大,执行一个即可,但是在正在使用中发现这个两个意义完全不一样的函数,区别如下:
1:Select函数中的fd_set参数维护着一个可读性检查队列或者可写性检查队列。
2:FD_SET,FD_ISSET,FD_CLR分别是对加入队列中的套接字句柄进行添加,判断和删除操作。
3:FD_ZERO这个函数是在套接字加入队列之前,对队列初始化为0。
4:FD_ZERO是将整个队列清零,FD_CLR只是删除队列中某个对应的套接字
Select工作流程
1:用FD_ZERO宏来初始化我们感兴趣的fd_set。
也就是select函数的第二三四个参数。
2:用FD_SET宏来将套接字句柄分配给相应的fd_set。
如果想要检查一个套接字是否有数据需要接收,可以用FD_SET宏把套接接字句柄加入可读性检查队列中
3:调用select函数。
如果该套接字没有数据需要接收,select函数会把该套接字从可读性检查队列中删除掉,
4:用FD_ISSET对套接字句柄进行检查。
如果我们所关注的那个套接字句柄仍然在开始分配的那个fd_set里,那么说明马上可以进行相应的IO操 作。
比如一个分配给select第一个参数的套接字句柄在select返回后仍然在select第一个参数的fd_set里,那么说明当前数据已经来了, 马上可以读取成功而不会被阻塞。