• 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在信号处理函数期间还会阻塞,这样也相当于保护了信号处理函数。

  • 相关阅读:
    winform 与 html 交互 简单案例
    Winform窗口弹出位置控制
    c#预处理指令
    最简单的数据绑定
    Asp.Net细节性问题精萃
    AjaxUploader使用
    Log4net对文件的支持
    Log4net对数据库的支持
    Log4net使用
    Log4net介绍
  • 原文地址:https://www.cnblogs.com/Flychown/p/6971578.html
Copyright © 2020-2023  润新知