选择()文件描述符集的系统调用和应用

选择()文件描述符集的系统调用和应用
在网络程序中,一个进程同时处理多个文件描述符是非常常见的。选择()系统调用使进程能够检测同时等待的多个输入/输出设备。当没有设备就绪时,选择()阻止,当任何设备就绪时,选择()返回。
select()以下列形式调用:
#包括&lt。sys/select.h&gt。
#包括&lt。sys/time.h&gt。
int select(int maxfd,fd _ set * readfds,fd _ set * writefds,fe _ set * exceptfds,const struct time val * time out);
选择的第一个参数是要在文件描述符集中检测的位数,它必须比要检测的最大文件描述符大至少1;参数readfds指定通过读取监控的文件描述符集;参数writefds指定要通过写入来监控的文件描述符集;参数exceptfds指定由异常条件监控的文件描述符集。
参数超时就像一个计时器:当指定的时间到了,不管是否有任何设备准备好了,它都会返回到调用。时间值的结构定义如下:
结构时间值{
长电视_秒;//表示几秒钟
long tv _ usec//意味着一些微妙之处
{}
超时取不同的值,调用显示不同的属性:
1.超时为0,调用立即返回;
2.超时为空,选择()调用被阻止,直到知道文件描述符已准备好;
3.超时是一个正整数,它是一个通用定时器。
当select调用返回时,select将清除readfds、writefds和exceptfds中所有未就绪的描述符,但已就绪的描述符除外。选择的返回值如下:
1.在正常情况下,返回就绪文件描述符的数量;
2.超时后没有设备准备好,返回值为0;
3.如果选择被信号中断,它将返回-1并将errno设置为eintr。
4.如果有错误,返回-1并设置相应的错误号。
系统提供四个宏来操作描述符集:
#包括&lt。sys/select.h&gt。
#包括&lt。sys/time.h&gt。
无效fd_set(int fd,fd _ set * fd set);
无效fd_clr(int fd,fd _ set * fd set);
无效fd_isset(int fd,fd _ set * fd set);
无效fd _ zero(fd _ set * fd set);
宏fd_set设置对应于文件描述符集fdset中的文件描述符fd的位(设置为1),宏fd_clr清除对应于文件描述符集fdset中的文件描述符fd的位(设置为0),宏fd_zero清除文件描述符集fdset中的所有位(设置所有位为0)。这三个宏用于在调用select之前设置描述符掩码位,fd_isset用于检测在调用select之后是否设置了文件描述符集fdset中对应于文件描述符fd的位。
过去,描述符集是作为整数位掩码实现的,但这种实现不适用于超过32个文件描述符。现在,描述符集通常由整数数组中的位字段表示,数组元素的每一位都对应一个文件描述符。例如,如果一个整数占用32位,整数数组的第一个元素表示文件描述符0到31,数组的第二个元素表示文件描述符32到63,依此类推。宏fd_s帝霸最新章节et将整数数组中fd文件描述符对应的位设置为1,宏fd_clr将fd文件描述符对应的位设置为0,宏fd_zero将整数数组中的所有位设置为0。假设在执行以下步骤后:
#包括&lt。sys/select.h&gt。
#包括&lt。sys/time.h&gt。
fd _ set readset
fd _ zero(& amp;read set);
fd _ set(5 & amp;read set);
fd _ set(33 & amp;read set);
对应于文件描述符集合readset中的文件描述符6和33的各个位被设置为1。
执行以下程序后:
fd _ clr(5 & amp;read set);
那么对应于文件描述符6的文件描述符集合readset的对应位被设置为0。
通常,操作系统通过宏fd_setsize声明在一个进程中通过选择可以操作的文件描述符的最大数量。例如:
在4.4bsd的头文件中,我们可以看到:
#ifndef fd_setsize
#定义fd_setsize 1024
#endif
在红帽linux的头文件中
# define _ _ fd _ setsize 1024
在头文件中
#包括&lt。bits/type . h & gt。
#定义fd _ setsize _ _ fd _ setsize
如果fd_setsize定义为1024,并且一个整数占用4个字节,即32位,则文件描述符集由包含32个元素的整数数组表示。我们可以在头文件中修改这个值来改变select使用的文件描述符集的大小,但是必须重新编译内核才能使修改后的值有效。当前版本的unix操作系统不限制fd_setsize的最大值,它通常只受内存和系统管理的限制。
在了解了文件描述符集的实现机制后,我生化全球最新章节们可以灵活地使用它。(以下程序在红帽linux 6.0下运行,函数fd_isempty用于判断文件描述符集是否为空;函数fd_fetch获取文件描述符集中的所有文件描述符)
#包括&lt。stdio.h&gt。
#包括&lt。string.h&gt。
#包括&lt。sys/time.h&gt。
#包括&lt。sys/select.h&gt。
结构my_fd_set{
fd _ set fs//定义文件描述符集fs
无符号int nconnect//文件描述符集中文件描述符的数量
无符号int nmaxfd//文件描述符集fs中最大的文件描述符
};
/*函数fd_isempty用于确定文件描述符集是否为空,如果为空,则返回1,否则返回0 *。
int fd _ isempty(struct my _ fd _ set * pfs)
{
int i;
/*文件描述符集fd_set由整数数组实现,因此整数数组myset中的元素数定义为内存中的字节数空由文件描述符集fd_set占用的字节数除以内存中的字节数空由整数占用的字节数。
*/
无符号整数[size of(fd _ set)/size of(int)];
/*设置文件描述符集pfs->: fs被复制到数组myset */
memcpy(我自己,amp。pfs-&gt。fs,sizeof(fd _ set));
对于(i = 0;i &lt。sizeof(fd _ set)/sizeof(int);i++)
/*如果myset的元素不是0,这意味着文件描述符集不是空,则函数返回0 */
如果(我自己)
返回0;
返回1;/*如果myset的所有元素都是0,并且描述文件的描述符集是空,则函数返回1 */
{}
/*函数fd_fetch对文件描述符集执行位操作,将1位转换为相应的文件描述符,然后对其执行输入/输出操作*/
void fd _ fetch(struct my _ fd _ set * pfs)
{
struct my _ fd _ set * tempset//定义临时结构指针
无符号整数[sizeof(fd_set)/sizeof(无符号整数)];
无符号整数i,nbit,nfind,ntemp
tempset = pfs。
memcpy(我自己,amp。tempset->。fs,sizeof(fd _ set));
/*将最大的文件描述符maxfd除以整数所占的位数,得到文件描述符集中maxfd的对应位对应于整数数组myset的对应元素的下标,以减少检索次数*/
nfind = tempset->。nmax fd/(sizeof(int)* 8);
对于(i = 0;i &lt。= nfind。i++) {
/*如果数组myset的一个元素是0,这意味着对应于这个元素的文件描述符集的所有32位都是0,那么继续判断下一个元素。*/
如果(myset == 0)继续;
/*如果数组myset的一个元素不是0,这意味着在对应于这个元素的文件描述符集的32位中有1。将myset分配给临时变量ntemp,对ntemp执行位操作,并将1位转换为相应的文件描述符*/
ntemp =我自己[i];
/* nbit记录整数的二进制数字,并执行& 1运算,直到整数的最高位,或者直到文件描述符集中的文件描述符的数量等于0 */
对于(nbit = 0;tempset->。n连接&amp。&amp。(nbit &lt。sizeof(int)* 8);nbit++版){
if (ntemp &amp。1) {
/*如果一个位为1,则对应的文件描述符为nbit+32*i,然后我们可以对其执行i/o操作。我刚刚在这里做了一个简单的展示。*/
printf(& # 34;i = %d,nbit = %d,文件描述为% d/n & # 34;,i,nbit,nbit+32 * i);
/*取出文件描述符后,将文件描述符集中的文件描述符数量减少1 */
tempset->。n连接-;{}
ntemp &gt。&gt。= 1;// ntemp向右移动一位
{}
{}
{}
/*以下主程序测试上述两个功能*/
main()
{
/*假设fd1、fd2和fd3是三个文件描述符,实际上它们可以是套接字描述符*/
int fd1 = 7,fd2 = 256,fd3 = 1023,isempty
结构my _ fd _ set connect _ set
connect _ set . n connect = 0;
connect _ set . nmax fd = 0;
fd _ zero(& amp;connect _ set . fs);
/*在fd _ set操作之前测试函数fd _ isempty
isempty = fd _ isempty(& amp;connect _ set);
printf(& # 34;isempty = % d/n & # 34;,isempty);
fd _ set(fd 1 & amp;connect _ set . fs);
fd _ set(fd 2 & amp;connect _ set . fs);
fd _ set(fd 3 & amp;connect _ set . fs);
connect _ set . n connect = 3;
connect _ set.nmaxfd = fd3
/*在fd _ set操作后,在将文件描述符添加到文件描述符集后测试fd _ isempty
isempty = fd _ isempty(& amp;connect _ set);
printf(& # 34;isempty = % d/n & # 34;,isempty);
/*测试函数fd_ fetch */
fd _ fetch (& amp;connect _ set);
{}
/*程序输出结果是:*/
isempty为1
isempty为0
i = 0,nbit = 7,文件描述为7
i = 8,nbit = 0,文件描述为256
i = 31,nbit = 31,文件描述为1023
文章来源:www.atolchina.com