在标准输入上测试select
实现参考了《UNIX环境高级编程》14.4.1和《UNIX系统编程手册》63.2.1。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using namespace std;
const int BUF_SIZE = 128;
int main(int argc, char **argv) {
fd_set rs;
FD_ZERO(&rs);
FD_SET(STDIN_FILENO, &rs);
for (int i = 0; i < 5; i++) {
timeval tv = {.tv_sec=2, .tv_usec=0};
fd_set rs_temp = rs;
int ret = select(STDIN_FILENO + 1, &rs_temp, NULL, NULL, &tv);
if (ret == -1) {
printf("select ret: %d, errno: %d\n", ret, errno);
return 1;
}
printf("select ret: %d\n", ret);
printf("if can read data from fd: %d is %s\n", STDIN_FILENO, FD_ISSET(STDIN_FILENO, &rs_temp) ? "true" : "false");
if (FD_ISSET(STDIN_FILENO, &rs_temp)) {
char buf[BUF_SIZE];
int n = read(STDIN_FILENO, buf, 5);
if (n == -1) {
printf("read failed, errno: %d\n", errno);
return 1;
}
buf[n] = '\0';
printf("success read %d bytes, buf: %s\n", n, buf);
}
}
return 0;
}hello world
是在第一次循环结果打印后,第二次调用select阻塞时输入的。 运行结果: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17select ret: 0
if can read data from fd: 0 is false
hello world
select ret: 1
if can read data from fd: 0 is true
success read 5 bytes, buf: hello
select ret: 1
if can read data from fd: 0 is true
success read 5 bytes, buf: worl
select ret: 1
if can read data from fd: 0 is true
success read 2 bytes, buf: d
select ret: 0
if can read data from fd: 0 is false
Process finished with exit code 0
非阻塞I/O
一个描述符阻塞与否并不影响select是否阻塞。1 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const int BUF_SIZE = 128;
using namespace std;
void set_fl(int fd, int flags) {
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
fprintf(stderr, "fcntl F_GETFL error\n");
exit(1);
}
val |= flags;
if (fcntl(fd, F_SETFL, val) < 0) {
fprintf(stderr, "fcntl F_SETFL error\n");
exit(1);
}
}
int main(int argc, char **argv) {
int n;
char buf[128];
set_fl(STDIN_FILENO, O_NONBLOCK);
n = read(STDIN_FILENO, buf, BUF_SIZE - 1);
printf("n: %d, errno: %d, str: %s\n", n, errno, strerror(errno));
fd_set rs;
FD_ZERO(&rs);
FD_SET(STDIN_FILENO, &rs);
for (int i = 0; i < 5; i++) {
fd_set rs_temp = rs;
timeval tv = {.tv_sec=2, .tv_usec=0};
int ret = select(STDIN_FILENO + 1, &rs_temp, NULL, NULL, &tv);
if (ret == -1) {
fprintf(stderr, "select ret: %d, errno: %d, str: %s\n", ret, errno, strerror(errno));
return 1;
}
printf("select ret: %d\n", ret);
printf("if can read data from fd: %d is %s\n", STDIN_FILENO, FD_ISSET(STDIN_FILENO, &rs_temp) ? "true" : "false");
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13n: -1, errno: 35, str: Resource temporarily unavailable
select ret: 0
if can read data from fd: 0 is false
select ret: 0
if can read data from fd: 0 is false
select ret: 0
if can read data from fd: 0 is false
select ret: 0
if can read data from fd: 0 is false
select ret: 0
if can read data from fd: 0 is false
Process finished with exit code 0
select阻塞中被信号中断
1 |
|
运行后给进程发SIGUSR1
信号。 1
2
3caught signal: 30, str: User defined signal 1: 30
select ret: -1
errno: 4, str: Interrupted system call
select支持的最大数量
1 |
|
1 | FD_SETSIZE: 1024 |
在本机的macOs
上$ uname -a
的结果为Darwin localhost 19.0.0 Darwin Kernel Version 19.0.0: Thu Oct 17 16:17:15 PDT 2019; root:xnu-6153.41.3~29/RELEASE_X86_64 x86_64
The behavior of these macros is undefined if a descriptor value is less than zero or greater than or equal to FD_SETSIZE, which is normally at least equal to the maximum number of descriptors supported by the system.2