socketpair + signal + select 的套路

1:起因

  最近在看代码时连续两次看到这三个函数的组合使用,为方便以后借鉴和回忆,先记录下来。

  这三个函数的应用场景是这样的:

  1.1 首先socketpair函数创建一对已连接套接字,返回的两个描述符(socketpair的第三个参数)都可以进行读写,但在单向通信的场景下一般将sv[0]作为读,sv[1]作为写。

  1.2 signal函数用于监听进程接收的信号并作相应处理,这里讲监听SIGTERM(这个信号一般是系统将要杀死进程前发送给进程的信号,SIGTERM大概过三秒之后系统就会再发送SIGKILL信号到进程杀死进程,SIGKILL信号是监听不到的)信号,所以信号处理函数不要过长,且函数是可重入的。

  1.3 select函数可以监听多个描述符的可读或可写状态实现I/O复用

  1.4 用法就是先得到sv[0]和sv[1],设置signal监听SIGTERM,信号处理函数里向sv[1]写捕捉到的信号,select监听sv[0]的可读状态,一旦可读就执行程序被杀死前的打扫工作。信号处理函数做的就是将获得的信号写给sv[0]而已。

2:函数用法简介

  2.1 socketpair

  原型:int socketpair(int domain, int type, int protocol, int sv[2])

  头文件:<sys/types.h> <sys/socket.h>

  参数:

    domain:一般是AF_UNIX,还有AF_LOCAL

    type:SOCK_STREAM和SOCK_DGRAM

    protocol:0

    sv:sv[0],sv[1]分别保存创建好的已连接的套接字对,两个均可读写

  2.2 signal

  原型:sighandler_t signal(int signum, sighandler_t handler)

  头文件:<signal.h>

  参数:

    signum:由SIGxxx组成的信号,具体可查 文章

    handler:是一个参数为int返回值为void的函数指针

  注:handler指向的信号处理函数一定要是可重入的,因为信号处理函数是异步触发的,如果处理函数不可重入则会导致意想不到的错误,同时信号处理函数要尽可能的短才好。什么是可重入可参考 文章

  2.3 select

  原型:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

  辅助函数: void FD_CLR(int fd, fd_set *set);
            int  FD_ISSET(int fd, fd_set *set);
            void FD_SET(int fd, fd_set *set);
            void FD_ZERO(fd_set *set);

  头文件:<sys/select.h> <sys/time.h> <sys/types.h>  <unistd.h>

  参数:

          nfds:所监听的描述符最大值加1

     readfds:监听的可读描述符集合,由FD_SET函数加入

          writefds:监听的可写描述符集合,由FD_SET函数加入

        exceptfds:监听的发生错误的描述符集合,由FD_SET函数加入

     timeout :select阻塞的超时时间

  返回值:

      >0:表示有几个描述达到了准备状态了,需要使用FD_ISSET来检验

      =0:表示超时时间到了还是没有准备好的描述符

      <0 : 出错

  特点:
       1:FD_SET将某个描述符记录在位图rfds中(rfds若是一个字节长度最多只能监听8个fd),select调用先清空rfds位图,在某个fd状态准备好后将它原先的位置1,之后FD_ISSET检测此fd对应的位图是否为1,为1即准备就绪。
       2:参数timeout是struct timeval *类型,表示阻塞时间
          NULL ---> 完全阻塞方式,一定要等到监听的fd有就绪的才返回(变成了可以监听多个fd的阻塞函数比如accept,recv等)
          0      ---> 不阻塞,select函数执行后立即返回
          >0    ---> 半阻塞,在timeout内阻塞,有状态改变即返回,timeout时间到也要返回
   注:select每次都会清空此参数的值,所以必须每次执行select前都要设置一下此参数值否则很可能意外变为不阻塞的select.

3:好处

  3.1 将信号处理过程与select关联起来易于管理。通常使用select还会监听其它要读写的文件描述符,这样把信号的处理也纳入进来一同管理程序分支显得少,更清晰。

  3.2 大大减少了信号处理函数的复杂度。因为信号是异步的,处理函数就必须是可重入的,使用socketpair + signal,让处理函数只做一个系统调用write动作,且signal在信号处理函数期间还会阻塞,这样也相当于保护了信号处理函数。

 

posted @ 2017-06-09 13:15  会飞的小丑  阅读(898)  评论(0编辑  收藏  举报