Linux中select函数学习及实例笔记
时间:2010-09-19 来源:hunaiquan
int select (int maxfdp1,fd_set *readset,fd_set * writeset,fd_set excpetset,const struct timeval *timeout); 返回值:准备好的描述符的正数目 0---超时 -1---出错! 其中最后一个参数是一个结构体的指针,它表示等待内核中的一组 描述符任一个准备好需要花费多久的时间!其中timeval指定了秒数和微秒数。 struct timeval{ long tv_sec;//秒数 long tv_usec;//微秒数 }; 将 timeout设置为空指针时,会永远等待下去,等待固定的时间:如果timeout指向的timeval中的具体的值时,会等待一个固定的时间,不等待 立刻返回,这时timeval中的tv_sec和tv_usec为0. select有三个可能的返回值。 1.正常情况下返回就绪的文件描述符个数;
2.经过了 timeout时长后仍无设备准备好,返回值为0;
3.如果select被某个信号中断,它将返回-1并设置errno为EINTR。
4. 如果出错,返回-1并设置相应的errno。 EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数n 为负值。
ENOMEM 核心内存不足
中间的三个参数readset writeset和excpetset指定我们要让内核测试读、写、异常条件所需的描述字!函数select使用描述字集,它一般是一个整型的数组,每个 数中的每一位代表一个描述符!
系统提供了4个宏对描述符集进行操作:
#include <sys/select.h>
#include <sys/time.h> //设置文件描述符集fdset中对应于文件描述符fd的位
void FD_SET(int fd, fd_set *fdset); //清除文件描述符集fdset中对应于文件描述符fd的位(设置为0)
void FD_CLR(int fd, fd_set *fdset); //清除文件描述符集fdset中的所有位(既把所有位都设置为0) void FD_ZERO(fd_set *fdset); //在调用select后使用FD_ISSET来检测文件描述符集 fdset中对应于文件描述符fd的位是否被设置。
void FD_ISSET(int fd, fd_set *fdset);
例如下面一段代码: fd_set readset;
FD_ZERO(&readset);
FD_SET(5, &readset);
FD_SET(33, &readset); 则文件描述符集readset中对应于文件描述符6和33的相应位被置为 1,如图1所示: 再执行如下程序后:
FD_CLR(5, &readset);
则文件描述符集readset对应于文件描述符6的相应位被置为0,如图2所示: 通常,操作系统通过宏FD_SETSIZE来声明在一个进程中select所能操作的文件描述符的最大数目。一般情况下被定义为1024.一个整数占4个 字节,既32位,那么就是用包含32个元素的整数数组来表示文件描述符集。我们可以在头文件中修改这个值来改变select使用的文件描述符集的大小,但 是需要注意的是:必须重新编译内核才能使修改后的值有效。 如果我们对其中的个一不感兴趣的话,可以设置为空指针。如果我们把三个都设为空指针,就实现了一个比sleep更准确的定时器。
注意select函数的第一个参数maxfdp1,是所有加入集合的句柄值的最大那个值还要加1。比如我们的描述符为1 4 5,那么maxfdp1就为6.描述符从0开始。当我们调用函数时,指定我们关心的描述符集,当返回时,指示那些描述符已经准备好了。怎么样才算准备好 呢!下面列出几种情况: 下列四个条件中的任何一个满足时,套接口准备好读:
(1) 套接口接收缓冲区中的数据字节数大于等于套接口接收缓冲区低潮限度的当前值。可以通过SO_REVILOAT来设置此低潮限度。
(2)连接的读这 一半关闭,也就是接收了FIN的TCP连接,
(3)套接口是一个监听套接口且已完成的连接数为非0.
(4)有一个套接口错误等处理。 下列三个条件中的任一个满足时,套接口准备好写:
(1) 套接口发送缓冲区的可用空间字节娄大于等于套接口发送缓冲区低潮限度的当前值且或者(i)套接口已连接,或者(ii)套接口不要求连接。
(2)连 接的写这一半关闭,对这样的套接口写操作将产生信号SIGPIEP。
(3)有一个套接口错误待处理。
下面是select函数的一个例子,主要参考网上的例子,并进行的适当的改变!并增加了客户端的程序。修改不fd[i]数组,可是实现动态的管理,也解决 了,当一个客户不断的断开再连接时,服务器也断开的情况。网址参考如下:
http://www.cnblogs.com/faraway/archive/2009/03/06/1404449.html
/*使用select函数可以以非阻塞的方式和多个socket通信。程序只是演示select函数的使用, 即使某个连接关闭以后也不会修改当前连接数,连接数达到最大值后会终止程序。
// select_server.c |
//客户端的一个简单的实现,只是为了证实一下,服务器端程序的正确性
//select_client.c
#include <stdio.h> |