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 删除。