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可以根据位图的方式来理解。
代码:
- #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:
- 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:
- Reading symbols from /home/fy/SystemV_ipc/select/run...done.
- (gdb) l
- 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);
- (gdb) b 7
- Breakpoint 1 at 0x4004a3: file select.c, line 7.
- (gdb) b 8
- Breakpoint 2 at 0x4004d2: file select.c, line 8.
- (gdb) b 9
- Breakpoint 3 at 0x4004e4: file select.c, line 9.
- (gdb) b 10
- Breakpoint 4 at 0x4004f6: file select.c, line 10.
- (gdb) l
- 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");
- (gdb) b 11
- Breakpoint 5 at 0x400508: file select.c, line 11.
- (gdb) b 12
- Breakpoint 6 at 0x400518: file select.c, line 12.
- (gdb) r
- Starting program: /home/fy/SystemV_ipc/select/run
- warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000
- Breakpoint 1, main () at select.c:7
- 7 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) c
- Continuing.
- Breakpoint 2, main () at select.c:8
- 8 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) c
- Continuing.也就是一个有16个元素的数组
- Breakpoint 3, main () at select.c:9
- 9 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) c
- Continuing.
- Breakpoint 4, main () at select.c:10
- 10 FD_SET(STDERR_FILENO,&fdset);
- (gdb) p fdset
- $5 = {__fds_bits = {3, 0 <repeats 15 times>}}注释:加入了STDOUT(1),最低八位为00000011,所以FD_SET应该是设置位的
- (gdb) c
- Continuing.
- Breakpoint 5, main () at select.c:11
- 11 FD_SET(7,&fdset);
- (gdb) p fdset
- $6 = {__fds_bits = {7, 0 <repeats 15 times>}}注释:加入了标准出粗输出(2),最低八位为00000111==7
- (gdb) c
- Continuing.
- Breakpoint 6, main () at select.c:12
- 12 if(FD_ISSET(STDOUT_FILENO,&fdset)!=0)注释:j加入了自定义7后,最低八位10000111==135
- (gdb) p fdset
- $7 = {__fds_bits = {135, 0 <repeats 15 times>}}
- (gdb) c
- Continuing.
- stdout has been set
- stdout has not been set
- Program 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开始。