欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

kqueue 接口

程序员文章站 2022-03-12 11:27:24
...
        kqueue 接口是从 FreeBSD 4.1 版引入的,它允许进程向内核注册描述所关注 kqueue 事件的事件过滤器。类似于 select,它也可以设置超时,此外,它还有异步 I/O、文件修改通知(例如文件被删除或修改时发出的通知)、进程跟踪(例如进程调用 exit 或 fork 时发出的通知)和信号处理功能。kqueue 接口包括如下 2 个函数和 1 个宏。
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
int kqueue(void);
int kevent(int kq, const struct kevent *changelist, int nchanges,
           struct kevent *eventlist, int nevents,
           const struct timespec *timeout);
void EV_SET(struct kevent *kev, uintptr_t ident, short filter,
            u_short flags, u_int fflags, intptr_t data, void *udata);

#include <sys/event.h>
struct kevent{
    uintptr_t    ident;    // identifier (e.g., file descriptor)
    short        filter;   // filter type (e.g., EVFILT_READ)
    u_short      flags;    // action flags (e.g., EV_ADD)
    u_int        fflags;   // filter-specific flags
    intptr_t     data;     // filter-specific data
    void         *udata;   // opaque user data
};

        其中,kevent 函数需要使用 kqueue 函数返回的 kqueue 描述符来注册所关注的事件和确定是否有所关注的事件发生。其参数 changelist 和 nchanges 表示对所关注事件做出的更改,若无更改则分别为 NULL 和 0。kevent 函数会在 nchanges 不为 0 时执行 changelist 数组中所请求的每个事件过滤器更改。对于条件已经触发的事件(包括刚在 changelist 中增设的那些事件),则由 eventlist 参数返回,它指向一个由 nevents 个元素构成的 kevent 结构数组。eventlist 中返回的事件数目将作为函数返回值,0 表示发生超时。超时通过 timeout 参数设置,其处理类似 select:NULL 阻塞进程,非 0 值指定明确的超时值,0 值执行非阻塞事件检测。
        在 kevent 结构中,flags 成员在调用时指定过滤器更改行为,在返回时额外给出条件,如下图所示。
kqueue 接口
            
    
    博客分类: 网络编程 网络编程kqueueselect 
        filter 成员指定的过滤器类型如下图所示。
kqueue 接口
            
    
    博客分类: 网络编程 网络编程kqueueselect 
        作为例子,这里将I/O 复用之select 函数一节中 str_cli 函数的 select 版本使用 kqueue 接口改下如下。
void str_cli(FILE *fp, int sockfd){
    struct stat st;
    int isfile = ((fstat(fileno(fp), &st) == 0) && (st.st_mode & S_IFMT) == S_IFREG);
    struct kevent kev[2];
    EV_SET(&kev[0], fileno(fp), EVFILT_READ, EV_ADD, 0, 0, NULL);
    EV_SET(&kev[1], sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
    int kq = kqueue();
    struct timespec ts;
    ts.tv_sec = ts.tv_nsec = 0;
    kevent(kq, kev, 2, NULL, 0, &ts);
    int nev, i, n, stdineof = 0;
    char buf[MAXLINE];
    for(;;){
        nev = kevent(kq, NULL, 0, kev, 2, NULL);
        for(i=0; i<nev; i++){
            if(kev[i].ident == sockfd){        // socket is readable
                if((n = read(sockfd, buf, MAXLINE)) == 0){
                    if(stdineof == 1)
                        return;                // normal termination
                    else{
                        printf("str_cli: server terminated prematurely\n");
                        exit(2);
                    }
                }
                write(fileno(stdout), buf, n);              
            }else if(kev[i].ident == fileno(fp)){   // input is readable
                n = read(fileno(fp), buf, MAXLINE);
                if(n > 0)
                    write(sockfd, buf, n);
                else if(n == 0 || (isfile && n == kev[i].data)){
                    stdineof = 1;
                    shutdown(sockfd, SHUT_WR);      // send FIN
                    kev[i].flags = EV_DELETE;
                    kevent(kq, &kev[i], 1, NULL, 0, &ts);    // remove kevent
                }
            }
        }
    }
}


参考书籍:
1、《UNIX 网络编程卷1:套接字联网API》第 14 章——高级 I/O 函数。
  • kqueue 接口
            
    
    博客分类: 网络编程 网络编程kqueueselect 
  • 大小: 24.7 KB
  • kqueue 接口
            
    
    博客分类: 网络编程 网络编程kqueueselect 
  • 大小: 16.1 KB