fd_set解析

来源:互联网 发布:mysql if语句 编辑:程序博客网 时间:2024/05/29 07:12

用到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可以根据位图的方式来理解。

代码:

[cpp] view plain copy
  1. #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);  
  11.         FD_SET(7,&fdset);  
  12.         if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)  
  13.                 printf("stdout has been set\n");  
  14.         else  
  15.                 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.         else  
  20.                 printf("stdout has not been set\n");  
  21.         return 0;  
  22. }  

下面是我的简单调试

[cpp] view plain copy
  1. GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-42.el5)  
  2. Copyright (C) 2009 Free Software Foundation, Inc.  
  3. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>  
  4. This is free software: you are free to change and redistribute it.  
  5. There is NO WARRANTY, to the extent permitted by law.  Type "show copying"  
  6. and "show warranty" for details.  
  7. This GDB was configured as "x86_64-redhat-linux-gnu".  
  8. For bug reporting instructions, please see:  
  9. <http://www.gnu.org/software/gdb/bugs/>...  
  10. Reading symbols from /home/fy/SystemV_ipc/select/run...done.  
  11. (gdb) l  
  12. 1       #include <stdio.h>  
  13. 2       #include <sys/select.h>  
  14. 3       #include <unistd.h>  
  15. 4       int main(void)  
  16. 5       {  
  17. 6               fd_set fdset;  
  18. 7               FD_ZERO (&fdset);  
  19. 8               FD_SET(STDIN_FILENO,&fdset);  
  20. 9               FD_SET(STDOUT_FILENO,&fdset);  
  21. 10             FD_SET(STDERR_FILENO,&fdset);  
  22. (gdb) b 7   
  23. Breakpoint 1 at 0x4004a3: file select.c, line 7.  
  24. (gdb) b 8  
  25. Breakpoint 2 at 0x4004d2: file select.c, line 8.  
  26. (gdb) b 9  
  27. Breakpoint 3 at 0x4004e4: file select.c, line 9.  
  28. (gdb) b 10  
  29. Breakpoint 4 at 0x4004f6: file select.c, line 10.  
  30. (gdb) l  
  31. 11              FD_SET(7,&fdset);  
  32. 12              if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)  
  33. 13                      printf("stdout has been set\n");  
  34. 14              else  
  35. 15                      printf("stdout has not been set\n");  
  36. 16              FD_CLR(STDOUT_FILENO,&fdset);  
  37. 17              if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)  
  38. 18                      printf("stdout has been set\n");  
  39. 19              else  
  40. 20                      printf("stdout has not been set\n");  
  41. (gdb) b 11  
  42. Breakpoint 5 at 0x400508: file select.c, line 11.  
  43. (gdb) b 12  
  44. Breakpoint 6 at 0x400518: file select.c, line 12.  
  45. (gdb) r  
  46. Starting program: /home/fy/SystemV_ipc/select/run   
  47. warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000  
  48. Breakpoint 1, main () at select.c:7  
  49. 7               FD_ZERO (&fdset);  
  50. (gdb) p fdset  注释:在执行FD_ZERO (&fdset);可以看下fdset里面到底放着什么  
  51. $1 = {__fds_bits = {0, 15774429, 194, 15774429, 140737488348710, 140737488348711, 0, 267984686016, 4195728, 4195203, 705412764499181569, 4195783, 0, 267984686016, 4195728, 0}}  
  52. (gdb) p sizeof(fdset)注释:看看fdset有多少位  
  53. $2 = 128  
  54. (gdb) c  
  55. Continuing.  
  56. Breakpoint 2, main () at select.c:8  
  57. 8               FD_SET(STDIN_FILENO,&fdset);  
  58. (gdb) p fdset 注释:在执行FD_ZERO (&fdset);后可以看下fdset里面到底放着什么,这也告诉了我们FD_ZERO的作用  
  59. $3 = {__fds_bits = {0 <repeats 16 times>}}注释:我的系统是64位,long占有8个字节,128个字节空间,所以是<repeats 16 times>(gdb) c  
  60. Continuing.也就是一个有16个元素的数组  
  61. Breakpoint 3, main () at select.c:9  
  62. 9               FD_SET(STDOUT_FILENO,&fdset);  
  63. (gdb) p fdset  注释:在执行FD_SET(STDIN_FILENO,&fdset);STDIN_FILENO为标准输入为0 最低八位00000001,0占了第0位  
  64. $4 = {__fds_bits = {1, 0 <repeats 15 times>}}  
  65. (gdb) c  
  66. Continuing.  
  67. Breakpoint 4, main () at select.c:10  
  68. 10              FD_SET(STDERR_FILENO,&fdset);  
  69. (gdb) p fdset  
  70. $5 = {__fds_bits = {3, 0 <repeats 15 times>}}注释:加入了STDOUT(1),最低八位为00000011,所以FD_SET应该是设置位的  
  71. (gdb) c  
  72. Continuing.  
  73. Breakpoint 5, main () at select.c:11  
  74. 11              FD_SET(7,&fdset);  
  75. (gdb) p fdset  
  76. $6 = {__fds_bits = {7, 0 <repeats 15 times>}}注释:加入了标准出粗输出(2),最低八位为00000111==7  
  77. (gdb) c  
  78. Continuing.  
  79. Breakpoint 6, main () at select.c:12  
  80. 12              if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)注释:j加入了自定义7后,最低八位10000111==135  
  81. (gdb) p fdset  
  82. $7 = {__fds_bits = {135, 0 <repeats 15 times>}}  
  83. (gdb) c  
  84. Continuing.  
  85. stdout has been set  
  86. stdout has not been set  
  87. Program exited normally.  
  88. (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开始。

原创粉丝点击