fd_set解析

来源:互联网 发布:手机微信刷屏软件 编辑:程序博客网 时间:2024/05/14 18:32

用到select,就难免不了要接触一下几个宏

  fd_set set;
  FD_ZERO(&set);
  FD_SET(read_fd,&set);
  select(MAX_NUM+1,&set,NULL,NULL,NULL);
  if(FD_ISSET(read_fd,set){……}

这几个经常是按这种次序组合出现的,之前虽然也用过,但说实话,也就是用,根本不知道怎么回事,现在有了初步的了解。

首先是 fd_set,这是什么?其实这是一个数组的宏定义,数组的类型是(unsigned) long型的(个人推测无符号),占有128位,无论是32位的linux下,还是64位下,他都是128个字节(128*8位=1024位,也就是可以检测1024个任务,这也是select默认的个数,可以通过编译内核修改),但是由于不同位数的系统下long型的长度不同,所以导致数组的元素个数也是不同的。理解fd_set可以根据位图的方式来理解。

代码:

#include <stdio.h>#include <sys/select.h>#include <unistd.h>int main(void){        fd_set fdset;        FD_ZERO (&fdset);        FD_SET(STDIN_FILENO,&fdset);        FD_SET(STDOUT_FILENO,&fdset);        FD_SET(STDERR_FILENO,&fdset);        FD_SET(7,&fdset);        if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)                printf("stdout has been set\n");        else                printf("stdout has not been set\n");        FD_CLR(STDOUT_FILENO,&fdset);        if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)                printf("stdout has been set\n");        else                printf("stdout has not been set\n");        return 0;}

下面是我的简单调试

GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-42.el5)Copyright (C) 2009 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/fy/SystemV_ipc/select/run...done.(gdb) l1       #include <stdio.h>2       #include <sys/select.h>3       #include <unistd.h>4       int main(void)5       {6               fd_set fdset;7               FD_ZERO (&fdset);8               FD_SET(STDIN_FILENO,&fdset);9               FD_SET(STDOUT_FILENO,&fdset);10             FD_SET(STDERR_FILENO,&fdset);(gdb) b 7 Breakpoint 1 at 0x4004a3: file select.c, line 7.(gdb) b 8Breakpoint 2 at 0x4004d2: file select.c, line 8.(gdb) b 9Breakpoint 3 at 0x4004e4: file select.c, line 9.(gdb) b 10Breakpoint 4 at 0x4004f6: file select.c, line 10.(gdb) l11              FD_SET(7,&fdset);12              if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)13                      printf("stdout has been set\n");14              else15                      printf("stdout has not been set\n");16              FD_CLR(STDOUT_FILENO,&fdset);17              if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)18                      printf("stdout has been set\n");19              else20                      printf("stdout has not been set\n");(gdb) b 11Breakpoint 5 at 0x400508: file select.c, line 11.(gdb) b 12Breakpoint 6 at 0x400518: file select.c, line 12.(gdb) rStarting program: /home/fy/SystemV_ipc/select/run warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000Breakpoint 1, main () at select.c:77               FD_ZERO (&fdset);(gdb) p fdset  注释:在执行FD_ZERO (&fdset);可以看下fdset里面到底放着什么$1 = {__fds_bits = {0, 15774429, 194, 15774429, 140737488348710, 140737488348711, 0, 267984686016, 4195728, 4195203, 705412764499181569, 4195783, 0, 267984686016, 4195728, 0}}(gdb) p sizeof(fdset)注释:看看fdset有多少位$2 = 128(gdb) cContinuing.Breakpoint 2, main () at select.c:88               FD_SET(STDIN_FILENO,&fdset);(gdb) p fdset 注释:在执行FD_ZERO (&fdset);后可以看下fdset里面到底放着什么,这也告诉了我们FD_ZERO的作用$3 = {__fds_bits = {0 <repeats 16 times>}}注释:我的系统是64位,long占有8个字节,128个字节空间,所以是<repeats 16 times>(gdb) cContinuing.也就是一个有16个元素的数组Breakpoint 3, main () at select.c:99               FD_SET(STDOUT_FILENO,&fdset);(gdb) p fdset  注释:在执行FD_SET(STDIN_FILENO,&fdset);STDIN_FILENO为标准输入为0 最低八位00000001,0占了第0位$4 = {__fds_bits = {1, 0 <repeats 15 times>}}(gdb) cContinuing.Breakpoint 4, main () at select.c:1010              FD_SET(STDERR_FILENO,&fdset);(gdb) p fdset$5 = {__fds_bits = {3, 0 <repeats 15 times>}}注释:加入了STDOUT(1),最低八位为00000011,所以FD_SET应该是设置位的(gdb) cContinuing.Breakpoint 5, main () at select.c:1111              FD_SET(7,&fdset);(gdb) p fdset$6 = {__fds_bits = {7, 0 <repeats 15 times>}}注释:加入了标准出粗输出(2),最低八位为00000111==7(gdb) cContinuing.Breakpoint 6, main () at select.c:1212              if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)注释:j加入了自定义7后,最低八位10000111==135(gdb) p fdset$7 = {__fds_bits = {135, 0 <repeats 15 times>}}(gdb) cContinuing.stdout has been setstdout has not been setProgram exited normally.(gdb) 

OK。这就是fd_set。
经过这个调试输出,那么对于这几个宏的作用,一定不会陌生了吧。

FD_ZERO(&set); /*将set清零使集合中不含任何fd*/
FD_SET(fd, &set); /*将fd加入set集合*/
FD_CLR(fd, &set); /*将fd从set集合中清除*/
FD_ISSET(fd, &set); /*测试fd是否在set集合中*/

对于这几个宏的实现,自然越是难事,只要你位操作熟练掌握。

PS:另外说一下,STDIN_FILENO==0,STDOUT_FILENO=1,STDERR_FILENO==2,这也说明了为什么我们建立某些文件描述符从3开始。

原创粉丝点击