select
函数让进程告诉内核,等待数个事件,某个事件发生或者达到指定时间时,唤醒进程。
例如,我们可以调用select
函数,通知内核,以下几种情况需要返回,
{1,4,5}
中任意一个描述字准备好被读{2,7}
中任意一个描述字准备好写{1,4}
中任意一个描述字发生异常待处理上述过程,表示进程告诉内核,进程关注哪些描述字(读写或者异常),以及等待多长时间。这里说的描述字并不仅限于套接口,任何描述字都可以应用于select
函数。
#include <sys/time.h>
#include <sys/select.h>
int select(int maxfdp1, fd_set * readset, fd_set * writeset, fd_set * exceptset, struct timeval * timeout)
最后一个参数,指定一个内核等待描述字的超时时间,结构体timeval
指定了秒级和微秒级成员。
struct timeval {
long tv_sec; /* seconds */
long tv_usec;/* and microseconds */
};
根据设置这一参数的不同,可能出现下列三种情况:
timeout
置为空指针。内核将永远等待下去,等待描述字准备好I/O或异常时才返回。timeout
中的时间设为不为0的固定值。内核会在描述字准备好I/O、异常,或者等待超过设定时间时返回。timeout
中的时间设为0。不等待,检查描述字后立即返回,即轮询(polling)。中间的三个参数,分别对应进程需要内核关注的读、写及异常的描述字集合,类型为fd_set
,例如,定义前面说到的被读的描述字集合:
fd_set rset;
FD_ZERO(&rset);
FD_SET(1, &rset);
FD_SET(4, &rset);
FD_SET(5, &rset);
如果对某个条件不关心,将其置为空指针即可,如果这三个参数都置为空指针,而最后的参数不为空指针。select
函数实际上就变成了一个比函数sleep
函数更精确的定时器(sleep
精确到秒)。
第一个参数指定内核关注描述字的边界,值是集合中最大的描述字加1,内核会从0开始,依次测试边界内的所有描述字。例如,对于上面{1,4,5}
的描述字集合,第一个参数的值应该是6。
描述字集合的几个参数均为值-结果参数,内核返回的时候会修改它们的值,告诉进程哪些描述字已经准备好。返回时,进程可以通过宏FD_ISSET
来测试描述字集合中的描述字,如果已经准备好,这些描述字的值会置为1。由于我们对结果的关注,所以一定要注意第一个参数的正确性,否则本该置为1的描述字可能会被置为0。
函数的返回值表示所有三个描述字集中已经准备好的总位数,有三种情况:
前面一直讨论的“描述字准备好”,在select
函数处理的时候,具体条件如下:
下面四个条件任意满足一个,套接口准备好读:
下面三个条件任意满足一个,套接口准备好写:
SIGPIPE
。对select
来说套接口准备好的条件的总结如下,
条件 | 是否可读 | 是否可写 | 是否异常 |
---|---|---|---|
有数据可读 | 是 | ||
关闭连接的读一半 | 是 | ||
给监听套接口准备好新连接 | 是 | ||
有可用于写的空间 | 是 | ||
关闭连接的写一半 | 是 | ||
待处理错误 | 是 | 是 | |
TCP带外数据 | 是 |
修改客户端的函数str_cli
,使用select
,这样服务器进程一终止,客户就能马上得到通知。原来版本的问题在于套接口上发生事件时,阻塞于fgets
调用的客户端无法及时处理。新版本则阻塞于select
调用,无论是标准输入,还是套接口事件,客户端都可以及时处理。
在新版函数str_cli
中,由select
处理以下条件:
read
返回大于0的值(数据字节数)。read
返回0(文件结束符)。read
返回-1,errno
则含有明确的错误码。str_cli
select
在新版的str_cli
函数中,使用select
函数,在返回可读条件时,分别处理可读套接口和可读标准输入。
如果select
返回套接口可读,则读取数据并输出打印。
如果select
返回标准输入可读,则调用fgets
阻塞读入一行,并写到套接口。
重新运行客户端和服务器,并依样找到服务器子进程的PID,杀掉进程,
[root@VM_0_6_centos ~]# ps -la
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 0 5774 5188 0 80 0 - 1596 inet_c pts/0 00:00:00 tcpserv04
1 S 0 8271 5774 0 80 0 - 1596 sk_wai pts/0 00:00:00 tcpserv04
0 R 0 8391 8353 0 80 0 - 38300 - pts/2 00:00:00 ps
[root@VM_0_6_centos ~]# kill -9 8271
此时客户端立即通知用户服务器进程已终止,
jackieluo@JACKIELUO-MB1 ~/Desktop/unpv13e/select ./tcpcli01 150.107.102.37
hello
hello
str_cli: server terminated prematurely
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。